Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

SpecValue
CoreARM Cortex-M0+, 48 MHz
Flash512 KB
RAM36 KB SRAM
Radio2.4 GHz IEEE 802.15.4 + BLE 5.4
Targetthumbv6m-none-eabi
I/OUART, SPI, I2C, ADC, GPIO
PackageQFN 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 MacDriver trait 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

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

  1. Open UniFlash and select CC2340R5
  2. Load the .hex or .bin file
  3. 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

SymptomCauseFix
Linker error: undefined RCL_*TI SDK not linkedSet CC2340_SDK_DIR or use --features stubs
portable-atomic errorsMissing featureEnsure features = ["unsafe-assume-single-core"]
No debug outputNo logger on Cortex-M0+Use probe-rs RTT for debug
Flash failsWrong chip selectedVerify CC2340R5 in probe-rs or UniFlash
RAM overflow36 KB limitReduce stack size, optimize allocations
Build without stubs failsMissing SDK librariesDownload TI SimpleLink F3 SDK

Roadmap

To bring the CC2340 backend to full RF operation:

  1. Embassy time driver — implement using CC2340R5 RTC or SysTick
  2. Proper GPIO HAL — replace register-level access with a Rust HAL
  3. Link real RCL — test with actual TI SDK libraries
  4. Interrupt wiring — connect RCL callbacks to Embassy signals
  5. Power management — leverage CC2340’s ultra-low-power sleep modes