AP(SMP)+CP 架构
架构概述
BK7258由三个core组成,为了更加方便应用层开发, 在原来的架构基础上, Armino SDK设计了新的AP+CP架构, 即SMP(CPU1+CPU2)+CPU0的模式。 其中CPU1+CPU2组成SMP系统, 称为AP, CPU0为单核系统, 称为CP。
AP(SMP)+CP 架构
如上图所示, AP和CP是独立的两个子系统, 其独立性体现为:
CP代码完全独立, 只包含Wi-Fi, BLE和少部分基础外设, 运行在cpu0上
AP代码完全独立, 包含多媒体方案, 客户主要在AP上开发, cpu1和cpu2实现SMP
从应用层的视角看, CP上运行Wi-Fi, BLE, 用于低功耗保活的LWIP协议栈, 及必要的外设;AP上运行多媒体模块, 给上层提供的LWIP协议栈, 应用经常使用的外设。 AP和CP之间通过Mailbox+共享内存通讯。从应用层的视角, AP和CP之间通过虚拟Uart接口通讯。 AP的Log通过MailBox发送到CP从UART0输出。
在新的架构下, 用户所有的开发都在AP上, 不再需要关注CP侧的开发。CP测的功能、AP与CP间的交互都由底层保证。
新架构的SDK组成也采用全新的目录, 具体结构如下:
ubuntu240:~/bk_avdk_smp$ tree -L 2
├── ap
│ ├── CMakeLists.txt
│ ├── components
│ ├── docs
│ ├── include
│ ├── Kconfig
│ ├── Makefile
│ ├── middleware
│ ├── properties
│ └── requirements.txt
├── cp
│ ├── CMakeLists.txt
│ ├── components
│ ├── docs
│ ├── include
│ ├── Kconfig
│ ├── Makefile
│ ├── middleware
│ ├── properties
│ └── requirements.txt
├── docs
│ ├── bk7258
│ └── version.json
├── LICENSE
├── Makefile
├── projects
│ ├── app
│ ├── app_ab
│ ├── doorbell
│ ├── lvgl
│ └── test
├── README_CN.md
├── README.md
└── tools
├── armino_doc.py
├── bk_bootloader_post.py
├── bk_smp_auto_partition.py
├── bk_smp_package.py
├── build_main.mk
├── build_tools
└── env_tools
AP和CP代码分别在各自的目录下, 两者间的代码完全独立。工程目录下包含ap_main文件夹和cp_main文件夹, 用来分别存放客户对于AP和CP的需求代码。
基于以上的目录结构, 构建过程如下:
先根据Project配置的分区表, 自动分区工具生成对应的分区表及相关文件
然后编译BK7258 AP系统, 生成SMP镜像
然后编译BK7258 CP系统, 生成bootloader和cp.bin镜像
将bootloader.bin,cp.bin,ap.bin根据分区表打包成all-app.bin
系统控制
资源划分
当前的内存划分为: 每个core内有16KB的ITCM和16KB DTCM空间, sram/psram以及flash空间是AP和CP共享的。
当前的SDK中已经按照资源的需求划分好了CP与AP的内存。
如果上层应用需要重新划分资源, 可以在工程中修改ram_regions.csv配置。
具体请参考 RAM资源分区配置 .
考虑到sram资源有限, 为了系统资源的充分利用。新架构中sram的布局也进行了调整。
当前sram内存布局如下(以doorbell工程为例):
/***************************************************************************
|--spinlock--|--hardware acc--|--ap sram--|--cp sram--|--pwr-mng--|--swap--|
****************************************************************************/
备注
建议客户不要随意改变该布局, 但可以根据实际需求调整ap和cp上sram的大小。
对于psram的使用, 考虑PSRAM可能需要掉电, CP上使用PSRAM仅限于动态Log等用完就释放的场景, CP上不允许将TASK或Queue或代码放到PSRAM上。
系统复位
架构采用的是全复位方案, 即CP或AP系统出现异常时, 整个系统全部复位。
也支持上层应用主动调用bk_reboot接口进行复位。
系统看门狗
由于看门狗硬件资源只有一份, 所以将其放在了CP上进行管理。由以下的宏进行配置:
CONFIG_INT_WDT=y
CONFIG_INT_WDT_PERIOD_MS=8000
CONFIG_TASK_WDT=y
CONFIG_TASK_WDT_PERIOD_MS=16000
喂狗的操作在CP上进行, 如果超过配置的时间没有喂狗, 会触发系统重启。
AP侧没有看门狗, 通过核间心跳机制来检测AP是否正常运行。
核间心跳
AP侧在启动后, 会定时向CP发送心跳包(默认间隔时间为2S)。该功能由宏CONFIG_SLAVE_HEART_BEAT控制, 默认开启。
当CP侧超过一定时间(与配置的INT WDT超时时间一致)没有接收到AP侧的心跳包, 则认为AP侧异常掉线, 会触发系统重启。
系统调试
系统的log由CP管理, 如果是CP侧的log, 则直接通过串口输出; 如果是AP侧的log, 由AP通过mailbox传送到CP侧, 再由串口输出。 CP侧的log不带任何前缀, AP侧的log会带ap0或ap1前缀。
如以下是系统启动的部分log示例:
os:I(7):mem_type start end size
os:I(7):-------- -------- -------- --------
os:I(7):itcm 0x20 0x3e88 15976
os:I(7):dtcm 0x20000000 0x200035f8 13816
os:I(7):ram 0x28064e00 0x2809e7f8 236024
os:I(7):non_heap 0x28064e00 0x280853a0 132512
os:I(7):iram 0x8064000 0x8064c40 3136
os:I(7):data 0x28064e00 0x28066128 4904
os:I(7):bss 0x28066140 0x2808539c 127580
os:I(7):heap 0x280853a0 0x2809e7f8 103512
os:I(7):psram 0x60700000 0x60720000 131072
os:I(8):create flash_svr, tcb=28088e00, stack=[280887d8-28088dd8:1536], prio=3
flash:I(8):id=0xc86517
ef:I(9):ENV start address is 0x007FA000, size is 8192 bytes.
ef:I(10):EasyFlash V4.1.0 is initialize success.
(11):ate enabled is 0
(11):driver_init end
sensor:I(11):saradc low value:[9bb]
sensor:I(11):saradc high value:[136a]
sensor:I(11):sdmadc low value:[6ec1]
sensor:I(11):sdmadc high value:[89e4]
init:I(11):reason - power on
init:I(11):regs - 0, 0, 0
init:I(11):armino rev:
init:I(11):armino soc id:53434647_72360101
bk_init:I(11):armino app init: Jun 6 2025 17:30:09
bk_init:I(11):verify id: unknown
bk_init:I(11):APP Version: unknown
nv:I(11):vnd_cal_version = 24-04-10 00:00:00
os:I(12):create event, tcb=28089ba8, stack=[28089380-28089b80:2048], prio=1
......
bluetoot:I(97):bk_bluetooth_init ok
os:I(98):create rosc_calib, tcb=28095028, stack=[28094000-28095000:4096], prio=1
(98):user app entry(0x2033561)
(99):reset_cpu1_core at: 02150000, start=1
ap0:AP:E(13):Mailbox send data fail[ret:-4103]
ap0:os:I(13):psram:0x60720000,size:655360
ap0:os:I(1):
ap0:os:I(13):mem_type start end size
ap0:os:I(13):-------- -------- -------- --------
ap0:os:I(13):itcm 0x20 0xa0 128
ap0:os:I(13):dtcm 0x20000004 0x20000004 0
ap0:os:I(13):ram 0x28010600 0x28060ff8 330232
ap0:os:I(13):non_heap 0x28010600 0x2801a400 40448
ap0:os:I(13):iram 0x8010000 0x8010508 1288
ap0:os:I(13):data 0x28010600 0x28010f44 2372
ap0:os:I(13):bss 0x28011d40 0x2801a3fc 34492
ap0:os:I(13):heap 0x2801a400 0x28060ff8 289784
ap0:os:I(13):psram 0x60720000 0x607c0000 655360
ap0:ef:I(14):ENV start address is 0x007FC000, size is 8192 bytes.
ap0:ef:I(32):EasyFlash V4.1.0 is initialize success.
ap0:(33):driver_init end
ap0:init:I(33):reason - power on
ap0:init:I(33):regs - 0, 0, 0
ap0:init:I(33):armino rev:
ap0:init:I(33):armino soc id:53434647_72360101
ap0:bk_init:I(33):armino app init: Jun 6 2025 17:30:00
ap0:bk_init:I(33):verify id: unknown
ap0:bk_init:I(33):APP Version: unknown
ap0:gpio:I(34):bk_gpio_driver_init:has inited
ap0:OS:I(34):create cli, tcb=2801ede8, stack=[2801d1c0-2801edc0:7168], prio=5, xCoreID=0
系统支持通过CLI命令对模块进行调试。CP侧的CLI命令不需要带任何前缀; AP侧的CLI命令必须带上 ap_cmd 前缀。
以下是CP侧和AP侧输入memshow命令的示例:
CP侧
memshow (输入命令)
os:I(108703):create shell_handle, tcb=28087270, stack=[28085648-28087248:7168], prio=5
cli:I(108704):================Static memory================
os:I(108704):
os:I(108704):mem_type start end size
os:I(108704):-------- -------- -------- --------
os:I(108704):itcm 0x20 0x3e88 15976
os:I(108704):dtcm 0x20000000 0x200035f8 13816
os:I(108704):ram 0x28064e00 0x2809e7f8 236024
os:I(108704):non_heap 0x28064e00 0x280853a0 132512
os:I(108704):iram 0x8064000 0x8064c40 3136
os:I(108704):data 0x28064e00 0x28066128 4904
os:I(108704):bss 0x28066140 0x2808539c 127580
os:I(108704):heap 0x280853a0 0x2809e7f8 103512
os:I(108704):psram 0x60700000 0x60720000 131072
cli:I(108704):================Dynamic memory================
name total free minimum peak
heap 103512 31688 26200 77312
psram 131072 131040 129104 1968
AP侧
ap_cmd memshow (输入命令)
os:I(2009):create shell_handle, tcb=280871e0, stack=[280855b8-280871b8:7168], prio=5
$ap0:cli:I(1857):================Static memory================
ap0:os:I(1857):
ap0:os:I(1857):mem_type start end size
ap0:os:I(1857):-------- -------- -------- --------
ap0:os:I(1857):itcm 0x20 0xa0 128
ap0:os:I(1857):dtcm 0x20000004 0x20000004 0
ap0:os:I(1857):ram 0x28010600 0x28060ff8 330232
ap0:os:I(1857):non_heap 0x28010600 0x2801a408 40456
ap0:os:I(1857):iram 0x8010000 0x8010508 1288
ap0:os:I(1857):data 0x28010600 0x28010f44 2372
ap0:os:I(1857):bss 0x28011d40 0x2801a404 34500
ap0:os:I(1857):heap 0x2801a408 0x28060ff8 289776
ap0:os:I(1857):psram 0x60720000 0x607c0000 655360
ap0:cli:I(1857):================Dynamic memory================
name total free minimum peak
heap 289784 250736 246400 43384
psram 655360 655328 655288 72
当系统发生了异常时, 如果开启了宏CONFIG_DEBUG_FIRMWARE或CONFIG_DUMP_ENABLE, 会有dump log输出。如果是CP侧发生了异常, dump log直接通过串口进行输出; 如果是AP侧发生了异常, dump log通过mailbox传输到CP侧, 由CP侧控制串口进行输出。
备注
为了兼容性, AP侧的cli命令统一带ap_cmd前缀, 因为此时AP为smp系统, 两个core可以看作一个整体。 但是AP侧的log 输出可能带有ap0 和 ap1, 这是为了区分具体是哪个core在运行代码输出的log。
如:
ap1:(95040):cpu2_test_task run core: 2
ap0:(95040):cpu1_test_task run core: 1
ap0:(96040):cpu1_test_task run core: 1
ap1:(96040):cpu2_test_task run core: 2
CP子系统
CP侧的功能比较简单, 主要分为以下部分:
运行Wi-Fi, BLE, 用于低功耗保活的LWIP协议栈
管理系统的log输出以及cli命令响应
管理核间心跳, 检测AP是否在线
系统的低功耗管理
AP子系统
概述
按照新的架构设计, Bk7258支持双核SMP架构, 这两个核共享所有的外设以及内存资源。每个core又各自含有自身的NVIC、cache等私有资源。核间可以通过mailbox交互必要的信息。
SMP 架构示意图
备注
1.图中的CPU0/CPU1指的是逻辑core id, 具体解释见下一章节, 后续我们统一用逻辑id来表述。
2.SMP中的mailbox指的是一条物理mailbox通道, 用来给两个内核间传递必要信息。
core id管理
按照新架构的设计, smp系统运行在物理CPU1和CPU2上。
从内核的视角看, 采用的是逻辑id, 即不管实际在什么物理核上, 总是按0、1这样排列;
而从应用层的视角, 由于某些配置的资源需要与具体的物理核绑定, 所以获取到的是物理id。通过os.h文件中的rtos_get_core_id()来得到。该接口返回值为1或者2, 代表物理的CPU1或CPU2。
在SMP启动过程中, 每个core会分别将自身的core id记录到特定位置。
重要
注意: 上层只允许调用rtos_get_core_id()来获取core id,返回值为CPU1_CORE_ID或CPU2_CORE_ID, 对应物理CPU1和CPU2。
SMP启动流程
在系统的引导和初始化阶段, 只有一个上下文, 只能由一个处理器来处理。
所以对于SMP系统, 一般会有一个先启动的core(称为primary core), 由其负责初始化整个系统的资源, 而其他的core则等待这些资源准备好后再开始工作。
对于新的SMP架构,primary core为Core 0(注意此处指的是逻辑ID),由Core 0负责引导这个系统的资源, 如各种外设、memory等。
Core 0在资源引导完毕后, 会释放Core 1,让Core 1开始启动, 之后开始进行系统的任务调度, 整个系统在此时就运行起来了。
SMP 启动流程
SMP编程注意事项
从软件的时间看, SMP系统与单CPU系统在编程上还是有一些差异的。这些差异主要体现在: