CC2340
Texas Instruments’ CC2340R5 is an ARM Cortex-M0+ SoC with a dedicated 2.4 GHz IEEE 802.15.4 radio, controlled through TI’s Radio Control Layer (RCL). The zigbee-rs CC2340 backend uses FFI bindings to TI’s precompiled RCL and MAC platform libraries.
Hardware Overview
| Spec | Value |
|---|---|
| Core | ARM Cortex-M0+, 48 MHz |
| Flash | 512 KB |
| RAM | 36 KB SRAM |
| Radio | 2.4 GHz IEEE 802.15.4 + BLE 5.4 |
| Target | thumbv6m-none-eabi |
| I/O | UART, SPI, I2C, ADC, GPIO |
| Package | QFN 5×5 mm (40 pins) |
Common Development Boards
- LP-EM-CC2340R5 — TI LaunchPad evaluation module
- BTN1 (DIO13): Join/Leave
- BTN2 (DIO14): Identify
- LED1 (DIO7): Network status
- LED2 (DIO6): Activity
Memory Map
FLASH : ORIGIN = 0x00000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 36K
Note: The CC2340R5 has 36 KB SRAM (not 64 KB — that’s the CC2340R53 variant).
Current Status
⚡ Stubs mode — The CC2340 backend compiles with stub FFI symbols in CI. Full radio operation requires linking TI’s SimpleLink Low Power F3 SDK libraries.
The backend is architecturally complete:
- Full
MacDrivertrait implementation - FFI bindings to TI’s RCL (Radio Control Layer)
- Frame construction and PIB management
- Example firmware with GPIO, LED, and button handling
What’s needed for real RF operation:
- TI SimpleLink Low Power F3 SDK (
CC2340_SDK_DIR) - RCL library (
rcl_cc23x0r5.a) - RF firmware patches (
pbe_ieee,mce_ieee,rfe_ieee) - A proper Embassy time driver using RTC or SysTick
Prerequisites
Rust Toolchain
rustup default nightly
rustup update nightly
# Add the Cortex-M0+ target
rustup target add thumbv6m-none-eabi
TI SimpleLink SDK (for real RF)
Download the SimpleLink Low Power F3 SDK from TI. Set the environment variable:
export CC2340_SDK_DIR=/path/to/simplelink_lowpower_f3_sdk
Flash Tool
Use TI’s UniFlash or a J-Link/CMSIS-DAP probe with probe-rs:
cargo install probe-rs-tools
Building
With Stubs (CI mode — no TI SDK needed)
cd examples/cc2340-sensor
cargo build --release --features stubs
With TI SDK (real radio)
cd examples/cc2340-sensor
CC2340_SDK_DIR=/path/to/sdk cargo build --release
CI Build Command
From .github/workflows/ci.yml:
# Toolchain: nightly with thumbv6m-none-eabi + rust-src + llvm-tools
cd examples/cc2340-sensor
cargo build --release --features stubs
# Firmware artifact extraction
OBJCOPY=$(find $(rustc --print sysroot) -name llvm-objcopy | head -1)
$OBJCOPY -O binary $ELF ${ELF}.bin
$OBJCOPY -O ihex $ELF ${ELF}.hex
Build Script (build.rs)
The build.rs conditionally links TI libraries when CC2340_SDK_DIR is set:
#![allow(unused)]
fn main() {
if let Ok(sdk_dir) = env::var("CC2340_SDK_DIR") {
// RCL (Radio Control Layer) library
println!("cargo:rustc-link-search={sdk}/source/ti/drivers/rcl/lib/ticlang/m0p");
println!("cargo:rustc-link-lib=static=rcl_cc23x0r5");
// RF firmware patches for IEEE 802.15.4
println!("cargo:rustc-link-lib=static=pbe_ieee_cc23x0r5");
println!("cargo:rustc-link-lib=static=mce_ieee_cc23x0r5");
println!("cargo:rustc-link-lib=static=rfe_ieee_cc23x0r5");
// Optional: ZBOSS platform libraries
// println!("cargo:rustc-link-lib=static=zb_ti_platform_zed");
}
}
.cargo/config.toml
[build]
target = "thumbv6m-none-eabi"
[unstable]
build-std = ["core", "alloc"]
Flashing
probe-rs
probe-rs run --chip CC2340R5 target/thumbv6m-none-eabi/release/cc2340-sensor
TI UniFlash
- Open UniFlash and select CC2340R5
- Load the
.hexor.binfile - Connect via XDS110 debug probe (on LaunchPad) and flash
MAC Backend Notes
The CC2340 MAC backend lives in zigbee-mac/src/cc2340/:
zigbee-mac/src/cc2340/
├── mod.rs # Cc2340Mac struct, MacDriver trait impl
└── driver.rs # Cc2340Driver — FFI bindings to TI RCL
Feature Flag
zigbee-mac = { features = ["cc2340"] }
Architecture
MacDriver trait methods
│
▼
Cc2340Mac (mod.rs)
├── PIB state (addresses, channel, config)
├── Frame construction
└── Cc2340Driver (driver.rs)
├── FFI → rcl_cc23x0r5.a (TI precompiled)
│ ├── RCL_init / RCL_open / RCL_close
│ ├── RCL_Command_submit / RCL_Command_pend
│ └── RCL_readRssi
├── IEEE 802.15.4 commands via RCL_CmdIeeeRxTx
├── TX completion: RCL callback → TX_SIGNAL
└── RX completion: RCL callback → RX_SIGNAL
TI RCL Overview
TI’s Radio Control Layer (RCL) is the abstraction between application code and the Low-level Radio Frontend (LRF). The LRF runs precompiled radio firmware patches that handle the actual RF modulation. The CC2340 backend interfaces with RCL through C FFI to submit IEEE 802.15.4 TX/RX commands.
Stubs Mode
When built with --features stubs, all FFI symbols (RCL_init, RCL_open,
rf_setChannel, etc.) are replaced with no-op stubs. This lets CI verify
the full Rust code compiles without needing TI’s proprietary libraries.
Example Walkthrough
The cc2340-sensor example implements a Zigbee 3.0 temperature & humidity
end device for the LP-EM-CC2340R5 LaunchPad.
Key Elements
GPIO (direct register access):
#![allow(unused)]
fn main() {
const GPIO_BASE: u32 = 0x4000_6000;
fn gpio_set_output(pin: u8) {
let doe_reg = (GPIO_BASE + 0x0C) as *mut u32;
// ...
}
}
Time driver stub:
#![allow(unused)]
fn main() {
// Minimal stub — a production firmware would use SysTick or RTC
impl Driver for Cc2340TimeDriver {
fn now(&self) -> u64 { 0 }
fn schedule_wake(&self, _at: u64, _waker: &core::task::Waker) {}
}
}
Device setup:
#![allow(unused)]
fn main() {
let mac = Cc2340Mac::new();
let mut device = ZigbeeDevice::builder(mac)
.device_type(DeviceType::EndDevice)
.manufacturer("Zigbee-RS")
.model("CC2340-Sensor")
.endpoint(1, PROFILE_HOME_AUTOMATION, 0x0302, |ep| {
ep.cluster_server(0x0000) // Basic
.cluster_server(0x0402) // Temperature
.cluster_server(0x0405) // Humidity
})
.build();
}
Logging Note
On Cortex-M0+ (no native CAS atomics), log::set_logger() is unavailable.
log::info!() etc. compile as no-ops without a registered logger. For real
debug output, use probe-rs RTT or SWD semihosting.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Linker error: undefined RCL_* | TI SDK not linked | Set CC2340_SDK_DIR or use --features stubs |
portable-atomic errors | Missing feature | Ensure features = ["unsafe-assume-single-core"] |
| No debug output | No logger on Cortex-M0+ | Use probe-rs RTT for debug |
| Flash fails | Wrong chip selected | Verify CC2340R5 in probe-rs or UniFlash |
| RAM overflow | 36 KB limit | Reduce stack size, optimize allocations |
| Build without stubs fails | Missing SDK libraries | Download TI SimpleLink F3 SDK |
Roadmap
To bring the CC2340 backend to full RF operation:
- Embassy time driver — implement using CC2340R5 RTC or SysTick
- Proper GPIO HAL — replace register-level access with a Rust HAL
- Link real RCL — test with actual TI SDK libraries
- Interrupt wiring — connect RCL callbacks to Embassy signals
- Power management — leverage CC2340’s ultra-low-power sleep modes