TI SimpleLink SDK Project Structure: Where Everything Lives and Why

You just imported your first CC2340 BLE example into Code Composer Studio, and the Project Explorer looks like someone detonated a filing cabinet. Folders point to places you didn’t know existed on your hard drive. Files you’re pretty sure you shouldn’t touch are indistinguishable from the ones you should. A mysterious syscfg/ directory seems to regenerate itself every time you build. If you’re coming from STM32CubeIDE or nRF Connect, this feels foreign. The TI ecosystem doesn’t organize things the way you’d expect.
The SimpleLink Low Power F3 SDK follows a consistent, predictable pattern across every single example project. Learn the layout once, and you can crack open any CC23xx project and immediately orient yourself. This article gives you that mental map, built around CCS and the CC2340R5 as our reference platform.
Two Separate Worlds: The SDK vs. Your Workspace
The single biggest source of confusion for newcomers is that the SDK and your project live in completely different places on disk, yet CCS makes them look like one unified tree.
The SDK installs to a fixed location. On Windows, that’s something like C:\ti\simplelink_lowpower_f3_sdk_8_xx_xx_xx. On macOS or Linux, an equivalent path under your home directory. This is a shared, global installation. Every project you create references it.
Your CCS workspace is separate. It holds project metadata, a handful of files that are truly “yours,” and a bunch of linked references that point back into that SDK installation.
┌─────────────────────────────────────┐
│ SDK Installation (shared, global) │
│ C:\ti\simplelink_lowpower_f3_sdk\ │
│ │
│ ├── source/ │
│ ├── kernel/ │
│ ├── tools/ │
│ └── examples/ │
└──────────────┬──────────────────────┘
│ linked references
▼
┌─────────────────────────────────────┐
│ Your CCS Workspace (per-project) │
│ ~/workspace_v12/my_ble_project/ │
│ │
│ ├── app/ ← YOUR code │
│ ├── syscfg/ ← generated │
│ └── .project, .ccsproject, etc. │
└─────────────────────────────────────┘The critical gotcha: because most source files are linked, not copied, editing them in CCS actually modifies the file inside the SDK installation directory. Your “fix” to a driver file will silently affect every other project on your machine. Rule of thumb: if you didn’t create the file and it lives under C:\ti\, don’t edit it directly.
The SDK Installation Directory, Top to Bottom
Let’s walk through what lives inside that SDK folder and why each piece exists.
simplelink_lowpower_f3_sdk_x_xx_xx_xx/
│
├── examples/ ← Starting-point projects (import these)
│ └── rtos/
│ └── CC2340R5/
│ ├── ble5/ ← BLE example projects
│ ├── drivers/ ← Peripheral driver demos
│ └── ...
│
├── source/ ← The actual SDK source code
│ ├── ti/
│ │ ├── ble5stack/ ← BLE protocol stack
│ │ ├── drivers/ ← TI Drivers (UART, SPI, GPIO, etc.)
│ │ ├── devices/ ← Device-specific headers & startup
│ │ └── display/, grlib/ ← Utility libraries
│ └── third_party/ ← FreeRTOS, mbedTLS, etc.
│
├── kernel/ ← RTOS kernel config & builds
│ ├── freertos/
│ └── nortos/
│
├── tools/ ← SysConfig, BLE tool configs, linker helpers
│
└── docs/ ← API reference, migration guidesA few things to flag here.
source/ti/ble5stack/ is where the BLE protocol stack lives. It ships primarily as precompiled libraries. You almost never modify anything in here directly. If you think you need to, you probably need to configure something differently in SysConfig instead.
examples/ is where you grab starter projects from. CCS imports these into your workspace. Think of them as templates.
docs/ is the most underused folder in the entire SDK. It contains per-module API documentation, the SDK User’s Guide, and migration guides between SDK versions. Before you spend 45 minutes on a forum search, check docs/ first.
Inside a Typical BLE Project: What CCS Actually Shows You
Open the basic_ble example after importing it, and CCS Project Explorer presents something like this:
basic_ble_app [CC2340R5 LaunchPad]
│
├── app/ ← YOUR application code
│ ├── app_main.c ← Entry point, task creation
│ ├── app_peripheral.c ← BLE peripheral role logic
│ └── app_data.c ← Custom data handling
│
├── Startup/
│ ├── main.c ← System init, calls app_main
│ └── ccfg.c ← Customer Configuration (trim, JTAG, etc.)
│
├── Drivers/ ← Linked to SDK's TI Drivers
│
├── BLE (stack)/ ← Linked to SDK's BLE stack libs
│
├── syscfg/ ← SysConfig-generated files
│ ├── ti_drivers_config.c ← Pin mux, driver init
│ ├── ti_ble_config.c ← BLE service/profile setup
│ └── ti_radio_config.c ← RF configuration
│
├── *.syscfg ← SysConfig input file (GUI-editable)
│
└── cc2340r5.cmd ← Linker command fileThis breaks down into three zones, and knowing which zone you’re in tells you exactly how to treat a file.
Zone 1: Your code. The app/ folder. This is where you spend 90% of your time. app_main.c creates your application tasks. app_peripheral.c handles BLE peripheral role events. These files are yours to hack apart, rename, restructure.
Zone 2: Generated code. The syscfg/ folder and everything in it. These files get regenerated on every build. Hand-editing them will be silently overwritten. We’ll cover SysConfig in a moment.
Zone 3: SDK references. Drivers/, BLE (stack)/, and most of Startup/. These are linked back to the SDK installation. Treat them as read-only. If you need different behavior from a driver, configure it via SysConfig or wrap it in your own code inside app/.
One exception worth noting: ccfg.c in Startup/ is often project-local and controls boot-level settings like JTAG access and flash protection. You may need to modify this, and that’s fine.
The linker command file (cc2340r5.cmd) is also fair game if you need to adjust memory regions, heap size, or stack allocation.
SysConfig: The Code Generator Running Behind the Scenes
SysConfig is probably the most important thing to understand early, because it controls a huge amount of your project’s behavior while being easy to overlook.
Double-click the .syscfg file in CCS and you get a graphical editor. Pin assignments, peripheral configuration, BLE service definitions, RF parameters: it’s all in here. When you build, SysConfig reads that .syscfg file and generates the C source files in syscfg/, including pin mux tables, driver initialization calls, and BLE profile setup code.
The golden rule: configure in SysConfig, never hand-edit generated files. Your changes will be overwritten on the next build, silently, with zero warnings.
If you need custom initialization logic that goes beyond what SysConfig offers, write it in your app/ code and run it after the generated init completes. That way your customizations survive every rebuild.
SysConfig also runs standalone and via CLI, which matters when you set up automated builds or CI pipelines later. But for now, the CCS-integrated GUI is where you’ll live.
How the Layers Connect at Runtime
Understanding the runtime architecture saves you from chasing bugs through the wrong layer.
┌─────────────────────────────────────┐
│ Your Application │ ← app/ folder
│ (app_main, app_peripheral) │
├─────────────────────────────────────┤
│ BLE-Stack / ICall │ ← Precompiled library from SDK
├─────────────────────────────────────┤
│ TI Drivers (UART, GPIO, SPI) │ ← source/ti/drivers/
├─────────────────────────────────────┤
│ FreeRTOS / NoRTOS Kernel │ ← kernel/
├─────────────────────────────────────┤
│ DriverLib / Device Hardware │ ← source/ti/devices/
└─────────────────────────────────────┘Your application code talks to two things: TI Drivers (for peripherals like UART, GPIO, SPI) and the BLE stack APIs (for wireless). You rarely drop below the Drivers layer into DriverLib unless you’re doing something specific with hardware registers.
ICall is worth knowing about even if you don’t touch it yet. It’s the inter-process communication layer between your application task and the BLE stack task; both run as separate FreeRTOS tasks. When your app calls a BLE API, ICall routes that message to the stack task. If you see ICall_ functions in example code, that’s what’s happening.
This layered structure means that when something breaks, you can usually narrow it down fast. Application logic bug? Check app/. Peripheral not initializing? Check SysConfig. BLE connection issue? Probably stack configuration, back to SysConfig’s BLE panel.
Quick Reference: “Where Do I Find…?”
| “I need to…” | Look here |
|---|---|
| Change pin assignments | .syscfg → SysConfig GUI, GPIO panel |
| Edit BLE service UUIDs or characteristics | .syscfg → BLE panel, or app/ profile code |
| Modify transmit power | .syscfg → RF settings |
| Adjust heap or stack sizes | .syscfg or cc2340r5.cmd linker file |
| Read the BLE stack API docs | SDK/docs/ble5stack/ble_user_guide/ |
| Find FreeRTOS configuration | SDK/kernel/freertos/builds/.../FreeRTOSConfig.h |
| Change boot or JTAG settings | Startup/ccfg.c |
| Add a new source file to the project | Create it in app/, add to CCS build |
If you’re building a device that talks to Hubble Network’s satellite or terrestrial infrastructure, the integration point is your app/ layer. Hubble’s device SDK introduction covers how the firmware SDK fits alongside your BLE application code, and the TI CC2340 FreeRTOS reference application shows a working CC2340 project with this exact SDK structure already wired up.
The Pattern That Repeats Across Every Example
Everything in a TI SimpleLink project fits into a simple framework. Two worlds: the SDK installation (shared, read-only in practice) and your project workspace (yours to modify). Three zones within your project: your code in app/, generated code in syscfg/, and SDK references everywhere else.
Once this clicks, every new example project you import will feel familiar. The folder names might shift slightly, and the specific BLE example might be simple_peripheral instead of basic_ble, but the underlying structure holds: app/ for your logic, .syscfg for configuration, linked SDK files for everything else.
Try this: import a second, different example project (pick a driver demo, not a BLE one). Open it in Project Explorer and see how the same pattern repeats, minus the BLE-specific folders. TI built one organizational pattern and stuck with it across the entire CC23xx example portfolio.
Hubble Network enables direct satellite connectivity for SimpleLink devices — no additional hardware, no gateway infrastructure. See how it works →