Architecture Overview
Introduction
The nRF5340 DK Matter Smart Light is built using a dual-core architecture with C++ Object-Oriented Programming (OOP) on top of the Zephyr RTOS. The system leverages the nRF5340’s dual ARM Cortex-M33 processors to separate application logic from radio protocol handling, following namespace-based modularization and inter-processor communication patterns.
Dual-Core System Architecture
The application utilizes both cores of the nRF5340:
APP Core (Cortex-M33 @ 128 MHz): Matter protocol, Thread networking, LED/button control
NET Core (Cortex-M33 @ 64 MHz): BLE radio, 802.15.4 radio, OpenThread MAC/PHY
Architecture Diagram
nRF5340 Dual-Core System Architecture
Hardware Resources
Core |
Flash Usage |
RAM Usage |
Primary Responsibilities |
|---|---|---|---|
APP Core |
75 KB (7.16%) |
34 KB (7.40%) |
Matter, Thread, UI |
NET Core |
142 KB (54.26%) |
31 KB (47.25%) |
BLE, 802.15.4 radio |
Design Patterns
Namespace-Based Modularization
All SDK modules use hierarchical C++ namespaces for clear organization:
namespace smarthome {
namespace protocol {
namespace matter {
class AppTask { /* ... */ };
class LightEndpoint { /* ... */ };
}
namespace thread {
class ThreadNetworkManager { /* ... */ };
}
namespace ble {
class BLEManager { /* ... */ };
}
}
namespace hw {
class ButtonManager { /* ... */ };
class UartManager { /* ... */ };
}
namespace ipc {
class IPCCore { /* ... */ };
}
}
// NET core uses separate namespace
namespace net {
class NetCoreManager { /* ... */ };
}
Namespace Hierarchy
C++ Namespace Structure
smarthome::
├── hw::
│ ├── ButtonManager
│ └── UartManager
│
├── protocol::
│ ├── matter::
│ │ ├── AppTask
│ │ ├── LightEndpoint
│ │ └── CommissioningDelegate
│ │
│ ├── thread::
│ │ ├── ThreadNetworkManager
│ │ └── NetworkResilienceManager
│ │
│ ├── ble::
│ │ └── BLEManager
│ │
│ └── radio::
│ └── RadioManager
│
├── ipc::
│ ├── IPCCore
│ └── MessageType (enum)
│
└── services::
└── wakeword::
└── ModelLoader
net:: (NET core only)
└── NetCoreManager
Note
PlantUML diagram available in CI/CD builds at doc/diagrams/namespace_hierarchy.puml
Function Pointer Callbacks
The application uses function pointers instead of std::function due to Zephyr’s minimal C++ support:
// Define callback type
using ButtonCallback = void (*)(bool pressed);
// Static callback function
static void button_callback(bool pressed) {
if (pressed) {
// Handle button press
}
}
// Register callback
ButtonManager::getInstance().setCallback(button_callback);
Inter-Processor Communication
The two cores communicate via RPMsg/OpenAMP protocol.
Inter-Processor Communication Sequence
Hardware interrupts for low latency * Asynchronous bidirectional communication * Message buffering in OpenAMP
C++ Features Used
Minimal C++ Standard Library
The application uses C++17 with minimal standard library support:
No STL containers (std::vector, std::map, etc.)
No
std::function(use function pointers)No exceptions (
-fno-exceptions)No RTTI (
-fno-rtti)Use C headers (
<string.h>not<cstring>)Manual memory management
Example patterns:
// Use function pointers, not std::function
using Callback = void (*)(int value);
// Use C headers
#include <string.h> // NOT <cstring>
#include <zephyr/kernel.h>
// Use Zephyr kernel types
K_KERNEL_STACK_MEMBER(stack, 1024); // NOT K_THREAD_STACK_MEMBER
// Include kernel.h BEFORE namespace declarations
// to avoid scoping issues with k_timer, k_mutex, etc.
Directory Structure
Source Code Organization
src/
├── app_core/ # APP Core entry point
│ ├── app_core.cpp # Main application logic
│ └── cpp_support.cpp # C++ runtime support
│
├── net_core/ # NET Core entry point
│ ├── net_core.hpp # NET core manager
│ └── net_core.cpp # Network processor state machine
│
├── app_core/ # APP Core entry point
│ ├── app_core.cpp # Main application logic
└── sdk/ # Shared SDK library (both cores)
├── protocol/ # Protocol implementations
│ ├── matter/ # Matter (CHIP) protocol [APP]
│ │ ├── app_task.cpp
│ │ ├── light_endpoint.cpp
│ │ └── commissioning_delegate.cpp
│ │
│ ├── thread/ # Thread networking [APP]
└── sdk/ # Shared SDK library (both cores)
├── protocol/ # Protocol implementations
│ ├── matter/ # Matter (CHIP) protocol [APP]
│ │ ├── app_task.cpp
│ │ ├── light_endpoint.cpp
│ │ └── commissioning_delegate.cpp
│ │
│ ├── thread/ # Thread networking [APP]
│ │ ├── thread_network_manager.cpp
│ │ └── network_resilience_manager.cpp
│ │
│ ├── ble/ # Bluetooth Low Energy [NET]
│ │ └── ble_manager.cpp
│ │
│ └── radio/ # IEEE 802.15.4 radio [NET]
│ └── radio_manager.cpp
│
├── hw/ # Hardware abstraction [APP]
│ ├── button/
│ │ └── button_manager.cpp
│ └── uart/
│ └── uart_manager.cpp
│
├── ipc/ # Inter-processor comm [BOTH]
│ └── ipc_core.cpp
│
└── services/ # Higher-level services
└── wakeword/ # ML model loading
└── model_loader.cpp
Legend:
[APP]- Used only by APP core[NET]- Used only by NET core[BOTH]- Shared by both cores
Note
PlantUML diagram available in CI/CD builds at doc/diagrams/directory_structure.puml``ucture.puml for PlantUML diagram with color coding.
Module Responsibilities
APP Core Modules
- AppTask (
sdk/protocol/matter/) Matter application state machine and event handling
- LightEndpoint (
sdk/protocol/matter/) Matter endpoint for LED control (on/off, brightness)
- ThreadNetworkManager (
sdk/protocol/thread/) Thread network initialization and management
- NetworkResilienceManager (
sdk/protocol/thread/) Network health monitoring and recovery
- ButtonManager (
sdk/hw/button/) GPIO button input with debouncing
- UartManager (
sdk/hw/uart/) Serial communication interface
NET Core Modules
- NetCoreManager (
net_core/) Network processor state machine and coordinator
- BLEManager (
sdk/protocol/ble/) Bluetooth Low Energy advertising and connections
- RadioManager (
sdk/protocol/radio/) IEEE 802.15.4 radio control and MAC layer
Inter-Core Communication
The APP and NET cores communicate via the IPC Core module using Zephyr’s OpenAMP/RPMsg:
Message Types
Radio Control: Commands from APP to NET for radio configuration
BLE Status: Connection state updates from NET to APP
Network Statistics: Link quality and performance data
Power Management: Sleep/wake coordination
Communication Flow
APP core calls
IPCCore::send(message)Message serialized and placed in shared memory
NET core interrupted via IPC mechanism
NET core
IPCCore::receive()callback invokedMessage deserialized and processed
- See Inter-Processor Communication for detailed IPC documentation.
Callback notification
Inter-Module Communication
The modules communicate through several mechanisms:
Direct Function Calls: Modules call each other’s public methods
Callbacks: Asynchronous event notification using function pointers
Message Queues: Thread-safe data passing (see Inter-Processor Communication)
Semaphores: Resource protection and synchronization
Initialization Sequence APP Core Initialization ========================
The APP core follows this initialization sequence in app_core.cpp:
extern "C" int main() {
// 1. Initialize hardware managers
smarthome::hw::ButtonManager::getInstance().init();
smarthome::hw::UartManager::getInstance().init();
// 2. Initialize IPC for inter-core communication
smarthome::ipc::IPCCore::getInstance().init();
// 3. Initialize Matter protocol stack
smarthome::protocol::matter::AppTask::getInstance().init();
smarthome::protocol::matter::LightEndpoint::getInstance().init();
// 4. Initialize Thread networking
smarthome::protocol::thread::ThreadNetworkManager::getInstance().init();
// 5. Start Matter application
smarthome::protocol::matter::AppTask::getInstance().startApp();
// 6. Main thread sleep
while (1) {
k_sleep(K_FOREVER);
}
}
NET Core Initialization
The NET core follows this initialization sequence in net_core.cpp:
extern "C" int main() {
// 1. Create NET core manager
net::NetCoreManager net_core;
// 2. Initialize (sets up BLE, Radio, IPC)
net_core.init();
// 3. Run state machine
net_core.run(); // Never returns
}
The NET core manager internally initializes:
smarthome::ipc::IPCCore- Inter-core communicationsmarthome::protocol::ble::BLEManager- Bluetooth radiosmarthome::protocol::radio::RadioManager- 802.15.4 radio
Build System
The application uses CMake with Zephyr’s build system:
CMakeLists.txt: Defines source files for both cores
prj_nrf5340_app.conf: APP core configuration
prj_nrf5340_net.conf: NET core configuration (requires
CONFIG_STATIC_INIT_GNU=yfor C++)Kconfig: Custom configuration symbols
Device Tree Overlays: Board-specific hardware configuration
Build Configuration
# APP Core sources
if(CONFIG_SOC_NRF5340_CPUAPP)
target_sources(app PRIVATE
src/app_core/app_core.cpp
src/sdk/protocol/matter/app_task.cpp
src/sdk/protocol/thread/thread_network_manager.cpp
src/sdk/hw/button/button_manager.cpp
src/sdk/ipc/ipc_core.cpp
)
endif()
# NET Core sources
if(CONFIG_SOC_NRF5340_CPUNET)
target_sources(app PRIVATE
src/net_core/net_core.cpp
src/sdk/protocol/ble/ble_manager.cpp
src/sdk/protocol/radio/radio_manager.cpp
src/sdk/ipc/ipc_core.cpp
)
endif()
Memory Layout
nRF5340 Memory Regions:
Core |
Region |
Size |
Usage |
|---|---|---|---|
APP |
Flash |
1 MB |
7.16% (75 KB) |
APP |
RAM |
448 KB |
7.40% (34 KB) |
NET |
Flash |
256 KB |
54.26% (142 KB) |
NET |
RAM |
64 KB |
47.25% (31 KB) |
The NET core uses more flash due to the OpenThread and BLE protocol stacks.
See Also
Inter-Processor Communication - IPC details
BLE Service - BLE implementation
- WiFi Service - WiFi/Thread networking
DRAM1
96 KB
38%
Heap and stacks