ACPU Usage Guide
1. ACPU Overview
The SF32LB57x and SF32LB58x series adopt a tri-core architecture: HCPU (high-performance computing), ACPU and LCPU (power-sensitive tasks such as BLE and sensor data processing). See HAL index for the full architecture description.
The ACPU role differs by chip series:
Chip series |
ACPU role |
|---|---|
SF32LB57x |
Audio and graphics processing |
SF32LB58x |
Audio DSP processing |
The ACPU runs an independent firmware image (RT-Thread based), which is built as a child project of the HCPU project and loaded into ACPU RAM by the second-stage bootloader at startup. The HCPU and ACPU communicate through the inter-core IPC Queue built on top of the mailbox.
1.1 Typical Use Cases
Audio codec offloading: opus encoder/decoder runs on ACPU, e.g.
example/multimedia/audio/opus.Voice 3A processing: ACPU tasks
ACPU_TASK_audio_3a_open/uplink/downlink/closehandle 3A processing.Graphics rendering: EPIC render list execution on ACPU (
ACPU_TASK_epic_rl), e.g.example/rt_device/gpu/render_list_mode.Custom computation tasks: user-defined tasks dispatched by
acpu_main(), e.g.example/multicore/acpu_task.
1.2 How HCPU and ACPU Interact
The HCPU initiates a task with
acpu_run_task(), which is a blocking call that returns after the ACPU finishes the task.The ACPU receives the task in
acpu_main(), executes it, and sends the result back withacpu_send_result().The underlying transport is the IPC Queue (bidirectional queues
sys_get_ha_ipc_queue/sys_get_ah_ipc_queue) with a semaphore for synchronization.
See Chapter 4 for the API details.
2. Enable and Configuration
An ACPU-enabled project consists of two parts: the HCPU project and the ACPU child project (see Chapter 3). Each project has its own configuration, which is edited with menuconfig.
2.1 Enable ACPU in the HCPU Project
In the project/hcpu directory, start menuconfig with the board name:
sdk.py menuconfig --board=ec-lb587
In the menuconfig interface:
Enable SiFli Built-in Components → ACPU Control Framework (
USING_ACPU_CTRL_FWK). This automatically selects On-chip Peripherals → ACPU (BSP_USING_ACPU) and the IPC Queue (USING_IPC_QUEUE).(Optional) Under SiFli Built-in Components → ACPU Control Framework, enable Enable Caller (
ACPU_CALLER_ENABLED, enabled by default on HCPU), which allows ACPU code to call HCPU services such as memory allocation and console output.
Press D to save the minimal configuration to proj.conf.
Notes:
BSP_USING_ACPUis only available on SF32LB57x and SF32LB58x chips (customer/boards/Kconfig_drv).Without a core suffix,
--boarddefaults to the HCPU core:ec-lb587andec-lb587_hcpuare equivalent.
2.2 Configure the ACPU Project
The ACPU child project has its own configuration. In the project/acpu directory, start menuconfig with the _acpu board suffix so that the ACPU-core board configuration is used:
sdk.py menuconfig --board=ec-lb587_acpu
Enable SiFli Built-in Components → ACPU Control Framework (USING_ACPU_CTRL_FWK; the IPC Queue is selected automatically).
2.3 Feature-Specific Options
Feature |
HCPU project ( |
ACPU project ( |
|---|---|---|
EPIC dual-core render list mode |
On-chip Peripherals → EPIC → Using epic render list API → EPIC Render List API Mode → select Using epic render list API in dual core HCPU mode ( |
Same menus → select Using epic render list API in dual core ACPU mode ( |
opus codec on ACPU |
– |
Third-Party Components → libopus ( |
ACPU calling HCPU services (memory allocation, console output) |
See 2.1 step 2 |
– |
The EPIC dual-core options automatically select USING_ACPU_CTRL_FWK (customer/boards/Kconfig_drv). The EPIC Render List API Mode choice depends on the core, so the HCPU and ACPU sides must each select their own dual-core mode in their own menuconfig session (with the _hcpu / _acpu board suffix). Refer to example/acpu/project/proj.conf for a complete EPIC-enabled ACPU project configuration.
3. Project Creation, Build and Flash
The ACPU runs a separate firmware image. In the SDK, the ACPU project is managed as a child project of the HCPU project and is built together with it.
3.1 Project Structure
Take example/multicore/acpu_task as an example:
example/multicore/acpu_task/
├── project/hcpu/ # HCPU project
├── project/acpu/ # ACPU child project
├── src/acpu/ # ACPU application code
└── src/hcpu/ # HCPU application code
3.2 Add the ACPU Child Project
In the HCPU project’s SConstruct.py, call AddChildProj with core="ACPU" to add the ACPU child project (example/multicore/acpu_task/project/hcpu/SConstruct.py):
acpu_proj_path = os.path.join(proj_path, '../acpu')
acpu_proj_name = 'acpu'
AddChildProj(acpu_proj_name, acpu_proj_path, False, core="ACPU")
3.3 Build and Flash
In the project/hcpu directory, build with the board name (only boards based on SF32LB57x/SF32LB58x support ACPU, e.g. ec-lb583, ec-lb587):
scons --board=ec-lb587
The build artifacts are generated under build_ec-lb587. Flash the image with:
build_ec-lb587/download.bat
When the board name carries the _hcpu suffix, the suffix can be omitted since HCPU is the default core (e.g. both ec-lb587 and ec-lb587_hcpu use the HCPU configuration).
3.4 ACPU Image Loading
The ACPU image is stored in the Flash and loaded into ACPU RAM by the second-stage bootloader at startup:
The flash table maps the ACPU image to the
DFU_FLASH_HCPU_EXT2partition. For example, the generatedftab.cplaces the image at flash address0x69100000and setsxip_base = 0x20200000, which corresponds to address 0 of the ACPU instruction space:
RT_USED const struct sec_configuration sec_config =
{
.magic = SEC_CONFIG_MAGIC,
.ftab[DFU_FLASH_HCPU_EXT2] = {.base = 0x69100000, .size = 0x0007C000, .xip_base = 0x20200000, .flags = 0},
.imgs[DFU_FLASH_IMG_IDX(DFU_FLASH_HCPU_EXT2)] = {.length = 0x00000AE4, .blksize = 512, .flags = DFU_FLAG_AUTO},
};
During startup, the second-stage bootloader copies the ACPU image from Flash to ACPU RAM (
example/boot_loader/project/sf32lb58x_v2/board/main.c, functionboot_images):
/* load extended img if present, such as ACPU img */
if (g_sec_config->imgs[DFU_FLASH_IMG_IDX(DFU_FLASH_HCPU_EXT2)].length != FLASH_UNINIT_32)
{
dfu_boot_img_in_flash(DFU_FLASH_HCPU_EXT2);
}
example/acpuis a generic ACPU project template used by other projects; modifying it affects all projects that reference it.
4. Communication and API Usage
The complete API is defined in middleware/include/acpu_ctrl.h (Doxygen reference: acpu_ctrl API). The transport between the two cores is the IPC Queue built on top of the mailbox (see IPC Queue and Mailbox).
4.1 HCPU-Side API
Function |
Description |
|---|---|
|
Initializes the framework: creates the HCPU→ACPU IPC queue and powers on the ACPU. It is exported with |
|
Sends a task to the ACPU and blocks until the task finishes. Returns the ACPU result buffer pointer and writes the error code to |
|
Controls the ACPU power domain. Power-on is normally performed by |
acpu_run_task() is implemented with a blocking semaphore: the caller thread is suspended until the ACPU sends the response, or the 1-second wait expires and the SDK raises an assertion (see middleware/acpu_ctrl/acpu_ctrl.c).
4.2 ACPU-Side API
Function |
Description |
|---|---|
|
The ACPU entry function. The weak default implementation dispatches the predefined tasks (opus, audio 3A, read/write, EPIC render list). Override it to handle custom tasks (see Chapter 5). |
|
Sends the task result back to the HCPU, which unblocks the pending |
|
Forwards a string to the HCPU console (requires |
|
Allocate/free memory on the HCPU side from ACPU code (requires |
|
Sends an assert notification to the HCPU. |
4.3 Task IDs
Task IDs are defined in middleware/include/acpu_ctrl.h:
Macro |
Value |
Description |
|---|---|---|
|
0 |
Invalid task |
|
1 |
User-defined task 0 |
|
2 |
User-defined task 1 |
|
3 |
opus encoder init |
|
4 |
opus encoder control |
|
5 |
opus encode |
|
6 |
opus decoder init |
|
7 |
opus decoder control |
|
8 |
opus decode |
|
9 |
audio 3A open |
|
10 |
audio 3A close |
|
11 |
audio 3A downlink |
|
12 |
audio 3A uplink |
|
13 |
read |
|
14 |
write |
|
15 |
EPIC render list |
|
16 |
Task count |
HCPU-side task IDs used when the ACPU calls back:
Macro |
Value |
Description |
|---|---|---|
|
0 |
Invalid task |
|
1 |
Allocate memory on HCPU |
|
2 |
Free memory on HCPU |
|
3 |
Print to HCPU console |
4.4 Notes and Limitations
The task message (
acpu_ctrl_ipc_msg_t) carries the parameter buffer pointer and the result value through the IPC queue. Per theacpu_run_task()documentation inacpu_ctrl.h, the parameter size is limited byACPU_TASK_INPUT_PARAM_SIZEand the result length byACPU_TASK_OUTPUT_VAL_SIZE.Do not call
acpu_run_task()from an interrupt context: it is a blocking call that suspends the calling thread.While waiting for the ACPU result, the framework requests
PM_SLEEP_MODE_IDLE, so the system does not enter a deeper sleep state during the call.If the ACPU returns
ACPU_ERR_ASSERT, the HCPU printsacpu assert:followed by the<file> <line>reported by the ACPU, and raises its own assertion.The ACPU image must be flashed correctly; otherwise the ACPU never responds and
acpu_run_task()times out and asserts.
5. Example Walkthrough
5.1 acpu_task: HCPU Dispatches a Task to ACPU
example/multicore/acpu_task is the minimal ACPU example. The HCPU registers a console command run_acpu (src/hcpu/main.c) that calls acpu_run_task():
static int run_acpu(int argc, char *argv[])
{
char *s;
if (argc < 2)
{
rt_kprintf("wrong argument\n");
return -1;
}
/* config ACPU to run specified task */
s = acpu_run_task(atoi(argv[1]) + ACPU_TASK_0, NULL, 0, NULL);
LOG_I(s);
return 0;
}
MSH_CMD_EXPORT(run_acpu, "run acpu")
The call blocks until the ACPU finishes the task. The ACPU entry acpu_main() has a weak default implementation in middleware/acpu_ctrl/acpu_main.c that handles the predefined task IDs; for task 0/1 it replies with "task_0" / "task_1", and for unknown IDs with "unknown task". The HCPU then logs the returned string:
msh />run_acpu 0
run_acpu 0
[I/main] task_0
msh />run_acpu 1
[I/main] task_1
msh />run_acpu 2
[I/main] unknown task
To implement custom tasks, define acpu_main(task_name, param) in src/acpu/main.c (the example ships an empty __acpu_main() placeholder there; a strong definition of acpu_main overrides the framework’s weak default), dispatch on task_name, execute the task, and return the result with acpu_send_result().
5.2 opus: Audio Codec on ACPU
example/multimedia/audio/opus runs the opus encoder/decoder on the ACPU. The ACPU project enables CONFIG_PKG_LIB_OPUS=y, and the HCPU delegates the codec operations through the ACPU_TASK_opus_* task IDs, e.g. (src/main.c):
#if defined(USING_ACPU_CTRL_FWK)
uint8_t error_code = 1;
opus_encode_ctl_arg_t arg;
arg.st = encoder;
arg.id = 0;
acpu_run_task(ACPU_TASK_opus_encoder_ctl, &arg, sizeof(arg), &error_code);
RT_ASSERT(error_code == 0);
#else
opus_encoder_ctl(encoder, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS));
...
#endif
The same pattern applies to ACPU_TASK_opus_encode, ACPU_TASK_opus_decode, etc.
5.3 4pdm: Audio Capture with 3A on ACPU
example/multimedia/audio/4pdm captures 4-channel PDM audio. When CONFIG_ANYKA_RUN_IN_ACPU=y is set in the HCPU project, the 3A processing runs on the ACPU through the ACPU_TASK_audio_3a_* tasks, and the ACPU child project is added in project/hcpu/SConstruct.
5.4 render_list_mode: GPU Rendering on ACPU
example/rt_device/gpu/render_list_mode runs EPIC render list execution on the ACPU. The HCPU project sets CONFIG_DRV_EPIC_NEW_API_DUAL_CORE_HCPU=y and reuses the generic ACPU template example/acpu/project as the child project (which enables CONFIG_DRV_EPIC_NEW_API_DUAL_CORE_ACPU=y). Render list jobs are delivered to the ACPU as ACPU_TASK_epic_rl.
6. Debugging and FAQ
6.1 ACPU Assert
When the ACPU hits an assertion, it calls acpu_send_assert(file, line) to report the location to the HCPU. The HCPU prints:
acpu assert:<file> <line>
and raises its own assertion (RT_ASSERT(0)). Check the reported ACPU source location to find the failure.
6.2 ACPU Logs
ACPU code can forward strings to the HCPU console with acpu_printf(). This requires ACPU_CALLER_ENABLED on the HCPU side (default enabled on HCPU). The console command acpu on / acpu off powers the ACPU domain on/off for debugging.
6.3 Memory
The ACPU image is copied to ACPU RAM at
0x20200000(address 0 of the ACPU instruction space) by the second-stage bootloader.Board-specific memory maps live under
customer/boards/<board>/{hcpu,lcpu,acpu}/(e.g.custom_mem_map.h).
6.4 Common Problems
Symptom |
Possible cause |
|---|---|
|
ACPU image not flashed, or |
The ACPU option does not appear in menuconfig |
The board is based on SF32LB52x/55x/56x, which have no ACPU core |
|
ACPU code failed at the reported file:line |
EPIC rendering is wrong or hangs |
|
7. References
Dual-Core Development note (SDK path:
docs/source/en/app_note/dualcore.md, SF32LB55x HCPU/LCPU)Memory Usage guide (SDK path:
docs/source/en/app_note/memory_usage.md, SF32LB55x)acpu_taskexample (SDK path:example/multicore/acpu_task)