Если вы когда‑либо работали с микроконтроллерами от компании Texas Instruments (TI), то 70%....90% вероятность, что вы их программировали в GUI‑IDE под названием Code Composer Studio (CCS). Как и у любой IDE CCS свойственны недостатки: ручные операции мышкой по настройке конфигураций, зависания GUI, отказ от сборки из консоли, калейдоскоп всяческих раcширений файлов, про которые даже местная техподдержка TI не в курсе, отказ от сборки проекта, если файл проекта находится вне пути на который ссылается переменная окружения WORKSPACE_LOC и прочее. Все эти проблемы можно разом решить, если собирать прошивки из самописных Makefile(ов) при помощи компилятора GNU ARM GCC.

О пользе makefile существует отдельный текст, вот он — Почему Важно Собирать С‑код из MakeFile. Если коротко, то с makefile(лами) намного проще делать полноценный DevOps, CI/CD и вообще масштабировать кодовую базу на другие процессорные архитектуры. Также сборка из makefile просто не позволяет разработчику производить неосознаных действий подобно тому как это повсеместно происходит в меню IDE.

Сборка прошивки для CC26x2 из Makefile

Фаза 1: подготовка оборудования, документации и софтвера

a--Что надо из оборудования?

#

оборудование

1

LapTop

2

отладочная плата LAUNCHXL-CC26X2R1

3

кабель USB-A-USB micro

В качестве отладочной платы я воспользуюсь платой LAUNCHXL-CC26X2R1. Там заложен микроконтроллер CC2652R1.

LAUNCHXL-CC26X2R1
LAUNCHXL-CC26X2R1

Вот примерная блок-схема платы LAUNCHXL-CC26X2R1. Мы видим, что тут есть сам микроконтроллер CC2652R1F и программатор отладчик XDS110.

Итак, что мы вообще знаем про микроконтроллер CC2652R1FRGZ?

Параметр

значение

Unit

Ядро

Arm Cortex-M4F

--

Архитектура

ARMv7-M

RF Core

Arm Cortex-M0

разрядность

32

bit

FPU

IEEE 754-compliant single-precision

RAM start

0x20000000

hex

GPRAM start

0x11000000

hex

GPRAM size

8

kByte

ROM start

0

hex

FLASH_CCFG start

0x00057fa8 (44тый сектор)

hex

количество секторов Flash памяти

44

dec

RAM size

80

kByte

ROM size

352

kByte

Flash sector size

8

kByte

Cache SRAM size

8

kByte

Peripherals

GPIO DAC UART ADC SPI I2C I2S AES TRNG Bluetooth 5.1, Timers MPU

-

Prog Interface

JTAG

-

CPU clock

48

MHz

Pin number

48

pin

GPIO count

31

pin

Порядок байтов

little Endian

-

Корпус микросхемы

RGZ (7-mm x 7-mm VQFN48)

Шаг между пинами

0.5

мм

Все эти данные об внутреннем устройстве микроконтроллера CC2652R1FRGZ нужны для формирования корректных опций компилятору и для написания корректного скрипта для компоновщика (*.ld файл).

b--Какие нужны доки?

Название дока

количество
страниц

комментарий

1

Using GCC/GDB With SimpleLink CC26xx/CC13xx

33

Перечень состава ToolChain(а) для GCC специально для TI MCU

2

CC2652R SimpleLink Multiprotocol 2.4 GHz Wireless MCU

70

флаер на микроконтроллер

3

CC13x2, CC26x2 SimpleLink Wireless MCU Technical Reference Manual

2083

спецификация микроконтроллера

4

Cortex-M3/M4F Instruction Set

221

Спецификация процессорного ядра

5

WCS037 LAUNCHXL-CC26X2R1

7

схемотехника отладочной платы

c--Что надо из софтвера?

#

Программа

назначение

1

OS Windows

операционная система

2

Eclipse

текстовый редактор

3

GNU Toolchain

компилятор, компоновщик, отладчик

4

UniFlash

прошивальщик

9

SmartRF Flash Programmer 2

еще один прошивальщик

10

XDS Emulation Software (EMUPack) (64-bit Windows)

Набор утилит в котором есть GDB сервер для микроконтроллеров CC26x2

8

C:\ti\simplelink_cc13xx_cc26xx_sdk_5_40_00_40

Исходные коды инициализации периферии микроконтроллеров семейства cc26xx

5

Build tools for Windows

набор вспомогательных консольных утилит для сборки программ. make, rm

12

make

универсальная утилита, которая управляет конвейером последовательности запуска консольных утилит на основе скрипта makefile

13

grep

утилита поиска файлов по ключевому регулярному выражению которое есть внутри найденных файлов

6

gdb_agent_console.exe

утилита GDB сервера для микроконтроллеров от TI

7

arm-none-eabi-gdb.exe

универсальная утилита GDB клиента

11

Tera Term

Терминал последовательного COM порта для диалога с прошивкой по UART

Проверить корректность установки GNU Toolchain можно выполнив команду arm-none-eabi-gcc --version в консоли Windows

Нужна утилита make. Её можно взять из состава MinGW.

Фаза 2: Подготовка скрипта настройки компоновщика.

Обычно сам С-код не особе аппаратно-зависмый. Наиболее аппаратно-зависимые исходники это файл настройки компоновщика. В GCC это *.ld файлы. Где же взять *.ld файл для микроконтроллера cc2652r1frgz? Ответ прост. Надо порыться прямо в SDK. При помощи утилиты grep я вскоре сузил место поиска до папки
C:\ti\simplelink_cc13xx_cc26xx_sdk_5_40_00_40\source\ti\devices\cc13x2_cc26x2\linker_files. Там и лежал подходящий файл разметки компоновщика cc26x2r1f.lds

/*
 @file      cc26x2r1f.lds
 @brief     CC26x2R1F rev2 linker configuration file for GNU compiler.
 */

/* Entry Point */
ENTRY( ResetISR )

/* System memory map */
MEMORY
{
    /* Application is stored in and executes from internal flash */
    FLASH (RX) : ORIGIN = 0x0, LENGTH = 0x57FA8
    /* Customer Configuration Area (CCFG) */
    FLASH_CCFG (RX) : ORIGIN = 0x57FA8, LENGTH = 88
    /* Application uses internal RAM for data */
    SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x14000
    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG
       (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
    GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x2000
}

/*. Highest address of the stack. Used in startup file .*/
_estack = ORIGIN(SRAM) + LENGTH(SRAM); /*end of SRAM .*/

/*. Generate a link error if heap and stack does not fit into RAM .*/
_Min_Heap_Size = 0;
_Min_Stack_Size = 0x100;

/* Section allocation in memory */
SECTIONS
{
    .text :
    {
        _text = .;
        KEEP(*(.vectors))
        *(.text*)
        *(.rodata*)
        *(.init)
        *(.fini*)
        *(.eh_frame*)
        _etext = .;
    } > FLASH = 0

   .ARM.exidx :
    {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    } > FLASH

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > FLASH

    .init_array :
    {
        _init_array = .;
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array*))
        _einit_array = .;
    } > FLASH

    .data :
    {
        _data = .;
        *(vtable)
        *(.data*)
        _edata = .;
    } > SRAM AT > FLASH
    _ldata = LOADADDR(.data);

    .bss :
    {
        __bss_start__ = .;
        _bss = .;
        *(.bss*)
        *(COMMON)
        _ebss = .;
        __bss_end__ = .;
    } > SRAM

    .ccfg :
    {
        KEEP(*(.ccfg));
    } > FLASH_CCFG

    /* User_heap_stack section, used to check that there is enough SRAM left */
    ._user_heap_stack :
    {
      . = ALIGN(4);
      . = . + _Min_Heap_Size;
      . = . + _Min_Stack_Size;
      . = ALIGN(4);
    } > SRAM

    .gpram :
    {
    } > GPRAM
}

Фаза 3: Подготовка startup кода

До запуска main() должен отрабатывать startup код. Где же найти файл для startup кода? Тут опять поиск grep(оп) внутри SDK по имени микроконтроллера и ключевому слову startup привел меня к файлу startup_gcc.c. У ST обычно startup написан на assembler, но у TI startup файл написан на С. Это хорошо и понятно. Внутри startup_gcc.c есть функция ResetISR(). Функция ResetISR инициализирует глобальные переменные (rwdata), обнуляет неинициализированные переменные (bss), активирует FPU и запускает функцию main(), а если main дала осечку - запускает зависание в бесконечном цикле. В startup коде также перечислены все обработчики прерываний для микроконтроллеров сс26x2.

/******************************************************************************
*  Filename:       startup_gcc.c
*  Revised:        $Date: 2017-06-01 16:01:48 +0200 (Thu, 01 Jun 2017) $
*  Revision:       $Revision: 17804 $
*
*  Description:    Startup code for CC26x2 device family for use with GCC.
*
******************************************************************************/

//*****************************************************************************
// Check if compiler is GNU Compiler
//*****************************************************************************
#if !(defined(__GNUC__))
#error "startup_gcc.c: Unsupported compiler!"
#endif

#include "../inc/hw_types.h"
#include "../driverlib/setup.h"

//*****************************************************************************
// Macro for weak symbol aliasing
//*****************************************************************************
#define WEAK_ALIAS(x) __attribute__ ((weak, alias(#x)))

//*****************************************************************************
// Forward declaration of the reset ISR and the default fault handlers.
//*****************************************************************************
void        ResetISR( void );
static void NmiSRHandler( void );
static void FaultISRHandler( void );
static void IntDefaultHandler( void );
extern int  main( void );

// Default interrupt handlers
void NmiSR(void) WEAK_ALIAS(NmiSRHandler);
void FaultISR(void) WEAK_ALIAS(FaultISRHandler);
void MPUFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void BusFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void UsageFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void SVCallIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void DebugMonIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void PendSVIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void SysTickIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void GPIOIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void I2CIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void RFCCPE1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void PKAIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AONRTCIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void UART0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXSWEvent0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void SSI0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void SSI1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void RFCCPE0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void RFCHardwareIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void RFCCmdAckIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void I2SIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXSWEvent1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void WatchdogIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer0AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer0BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer1AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer1BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer2AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer2BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer3AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void Timer3BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void CryptoIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void uDMAIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void uDMAErrIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void FlashIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void SWEvent0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXCombEventIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AONProgIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void DynProgIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXCompAIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXADCIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void TRNGIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void OSCIntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void AUXTimer2IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void UART1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);
void BatMonIntHandler(void) WEAK_ALIAS(IntDefaultHandler);


//*****************************************************************************
// The following are constructs created by the linker, indicating where the
// the "data" and "bss" segments reside in memory.
//*****************************************************************************
extern uint32_t _ldata;
extern uint32_t _data;
extern uint32_t _edata;
extern uint32_t _bss;
extern uint32_t _ebss;
extern uint32_t _estack;

//*****************************************************************************
//! The vector table. Note that the proper constructs must be placed on this to
//! ensure that it ends up at physical address 0x0000.0000 or at the start of
//! the program if located at a start address other than 0.
//*****************************************************************************
__attribute__ ((section(".vectors"), used))
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((unsigned long)&_estack),
                                            //  0 The initial stack pointer
    ResetISR,                               //  1 The reset handler
    NmiSR,                                  //  2 The NMI handler
    FaultISR,                               //  3 The hard fault handler
    MPUFaultIntHandler,                     //  4 Memory Management (MemManage) Fault
    BusFaultIntHandler,                     //  5 The bus fault handler
    UsageFaultIntHandler,                   //  6 The usage fault handler
    0,                                      //  7 Reserved
    0,                                      //  8 Reserved
    0,                                      //  9 Reserved
    0,                                      // 10 Reserved
    SVCallIntHandler,                       // 11 Supervisor Call (SVCall)
    DebugMonIntHandler,                     // 12 Debug monitor handler
    0,                                      // 13 Reserved
    PendSVIntHandler,                       // 14 The PendSV handler
    SysTickIntHandler,                      // 15 The SysTick handler
    //--- External interrupts ---
    GPIOIntHandler,                         // 16 AON edge detect
    I2CIntHandler,                          // 17 I2C
    RFCCPE1IntHandler,                      // 18 RF Core Command & Packet Engine 1
    PKAIntHandler,                          // 19 PKA Interrupt event
    AONRTCIntHandler,                       // 20 AON RTC
    UART0IntHandler,                        // 21 UART0 Rx and Tx
    AUXSWEvent0IntHandler,                  // 22 AUX software event 0
    SSI0IntHandler,                         // 23 SSI0 Rx and Tx
    SSI1IntHandler,                         // 24 SSI1 Rx and Tx
    RFCCPE0IntHandler,                      // 25 RF Core Command & Packet Engine 0
    RFCHardwareIntHandler,                  // 26 RF Core Hardware
    RFCCmdAckIntHandler,                    // 27 RF Core Command Acknowledge
    I2SIntHandler,                          // 28 I2S
    AUXSWEvent1IntHandler,                  // 29 AUX software event 1
    WatchdogIntHandler,                     // 30 Watchdog timer
    Timer0AIntHandler,                      // 31 Timer 0 subtimer A
    Timer0BIntHandler,                      // 32 Timer 0 subtimer B
    Timer1AIntHandler,                      // 33 Timer 1 subtimer A
    Timer1BIntHandler,                      // 34 Timer 1 subtimer B
    Timer2AIntHandler,                      // 35 Timer 2 subtimer A
    Timer2BIntHandler,                      // 36 Timer 2 subtimer B
    Timer3AIntHandler,                      // 37 Timer 3 subtimer A
    Timer3BIntHandler,                      // 38 Timer 3 subtimer B
    CryptoIntHandler,                       // 39 Crypto Core Result available
    uDMAIntHandler,                         // 40 uDMA Software
    uDMAErrIntHandler,                      // 41 uDMA Error
    FlashIntHandler,                        // 42 Flash controller
    SWEvent0IntHandler,                     // 43 Software Event 0
    AUXCombEventIntHandler,                 // 44 AUX combined event
    AONProgIntHandler,                      // 45 AON programmable 0
    DynProgIntHandler,                      // 46 Dynamic Programmable interrupt
                                            //    source (Default: PRCM)
    AUXCompAIntHandler,                     // 47 AUX Comparator A
    AUXADCIntHandler,                       // 48 AUX ADC new sample or ADC DMA
                                            //    done, ADC underflow, ADC overflow
    TRNGIntHandler,                         // 49 TRNG event
    OSCIntHandler,                          // 50 Combined event from Oscillator control
    AUXTimer2IntHandler,                    // 51 AUX Timer2 event 0
    UART1IntHandler,                        // 52 UART1 combined interrupt
    BatMonIntHandler                        // 53 Combined event from battery monitor
};


//*****************************************************************************
//! This is the code that gets called when the processor first starts execution
//! following a reset event. Only the absolutely necessary set is performed,
//! after which the application supplied entry() routine is called. Any fancy
//! actions (such as making decisions based on the reset cause register, and
//! resetting the bits in that register) are left solely in the hands of the
//! application.
//*****************************************************************************
void
ResetISR(void){
    uint32_t *pSrc;
    uint32_t *pDest;

    // Final trim of device
    SetupTrimDevice();
    
    // Copy the data segment initializers from FLASH to SRAM.
    pSrc = &_ldata;
    for(pDest = &_data; pDest < &_edata; )    {
        *pDest++ = *pSrc++;
    }

    // Zero fill the bss segment.
    __asm("    ldr     r0, =_bss\n"
          "    ldr     r1, =_ebss\n"
          "    mov     r2, #0\n"
          "    .thumb_func\n"
          "zero_loop:\n"
          "        cmp     r0, r1\n"
          "        it      lt\n"
          "        strlt   r2, [r0], #4\n"
          "        blt     zero_loop");

    // Enable the FPU
    // CPACR is located at address 0xE000ED88
    // Set bits 20-23 in CPACR to enable CP10 and CP11 coprocessors
    __asm("    ldr.w   r0, =0xE000ED88\n"
          "    ldr     r1, [r0]\n"
          "    orr     r1, r1, #(0xF << 20)\n"
          "    str     r1, [r0]\n");

    // Call the application's entry point.
    main();
    // If we ever return signal Error
    FaultISR();
}

//*****************************************************************************
//! This is the code that gets called when the processor receives a NMI. This
//! simply enters an infinite loop, preserving the system state for examination
//! by a debugger.
//*****************************************************************************
static void
NmiSRHandler(void){
    while(1)    {    }
}

//*****************************************************************************
//! This is the code that gets called when the processor receives a fault
//! interrupt. This simply enters an infinite loop, preserving the system state
//! for examination by a debugger.
//*****************************************************************************
static void
FaultISRHandler(void){
    while(1)    {    }
}

//*****************************************************************************
//! This is the code that gets called when the processor receives an unexpected
//! interrupt. This simply enters an infinite loop, preserving the system state
//! for examination by a debugger.
//*****************************************************************************
static void
IntDefaultHandler(void){
    // Go into an infinite loop.
    while(1)    {    }
}

Фаза 4: Подготовка области конфигурации устройства

Микроконтроллеры СС26x2 отличаются тем, что у TI MCU в последнем (43м) секторе Flash памяти лежит бинарная структура, которая отвечает за аппаратные настройки микросхемы. Там прописаны заводские конфигурации и пользовательские конфигурации. Такие как MAC адрес, настройка загрузчика, мощность излучения RF части. Этот последний сектор надо корректно проинициализировать или вообще не трогать с самой покупки микроконтроллера. За формирование конфигов устройства отвечает файл-исходник ccfg.c.

Если в последнем секторе вдруг окажутся случайные числа, то микроконтроллер просто не заведется при hot reset, а на проводе кварца будет какой-то случайный рваный сигнал.

/******************************************************************************
*  Filename:       ccfg.c
*  Revised:        $Date: 2017-11-02 11:36:28 +0100 (Thu, 02 Nov 2017) $
*  Revision:       $Revision: 18030 $
*  Description:    Customer Configuration for:
*                  CC13x2, CC13x4, CC26x2, CC26x4 device family (HW rev 2).
*****************************************************************************/

#ifndef __CCFC_C__
#define __CCFC_C__

#include <stdint.h>
#include "../inc/hw_types.h"
#include "../inc/hw_ccfg.h"
#include "../inc/hw_ccfg_simple_struct.h"

//*****************************************************************************
// Introduction
// This file contains fields used by Boot ROM, startup code, and SW radio
// stacks to configure chip behavior.
//
// Fields are documented in more details in hw_ccfg.h and CCFG.html in
// DriverLib documentation (doc_overview.html -> CPU Domain Memory Map -> CCFG).
//
// PLEASE NOTE:
// It is not recommended to do modifications inside the ccfg.c file.
// This file is part of the CoreSDK release and future releases may have
// important modifications and new fields added without notice.
// The recommended method to modify the CCFG settings is to have a separate
// <customer_ccfg>.c file that defines the specific CCFG values to be
// overridden and then include the TI provided ccfg.c at the very end,
// giving default values for non-overriden settings.
//
// Example:
// #define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE  0xC5 // Enable ROM boot loader
// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION     0x3  // LF RCOSC
// //---- Use default values for all others ----
// #include "<project-path>/source/ti/devices/<device>/startup_files/ccfg.c"
//
//*****************************************************************************

//*****************************************************************************
// Internal settings, forcing several bit-fields to be set to a specific value.
//*****************************************************************************

//#####################################
// Force VDDR high setting (Higher output power but also higher power consumption)
// This is also called "boost mode"
// WARNING: CCFG_FORCE_VDDR_HH must not be set to 1 if running in external regulator mode.
//#####################################

#ifndef CCFG_FORCE_VDDR_HH
#define CCFG_FORCE_VDDR_HH                              0x0        // Use default VDDR trim
// #define CCFG_FORCE_VDDR_HH                           0x1        // Force VDDR voltage to the factory HH setting (FCFG1..VDDR_TRIM_HH)
#endif

//*****************************************************************************
// Set the values of the individual bit fields.
//*****************************************************************************

//#####################################
// Alternative DC/DC settings
//#####################################

#ifndef SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING
#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING    0x0    // Alternative DC/DC setting enabled
// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING 0x1    // Alternative DC/DC setting disabled
#endif

#if ( CCFG_FORCE_VDDR_HH )
#define SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN                  0xC    // Special VMIN level (2.5V) when forced VDDR HH voltage
#else
#ifndef SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN
#define SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN                  0x8    // 2.25V
#endif
#endif

#ifndef SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN
#define SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN         0x0        // Dithering disabled
// #define SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN      0x1        // Dithering enabled
#endif

#ifndef SET_CCFG_MODE_CONF_1_ALT_DCDC_IPEAK
#define SET_CCFG_MODE_CONF_1_ALT_DCDC_IPEAK             0x0        // Peak current
#endif

//#####################################
// XOSC override settings
//#####################################

#ifndef SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR
// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR     0x0        // Enable override
#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR        0x1        // Disable override
#endif

#ifndef SET_CCFG_MODE_CONF_1_DELTA_IBIAS_INIT
#define SET_CCFG_MODE_CONF_1_DELTA_IBIAS_INIT           0x0        // Delta = 0
#endif

#ifndef SET_CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET
#define SET_CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET         0x0        // Delta = 0
#endif

#ifndef SET_CCFG_MODE_CONF_1_XOSC_MAX_START
#define SET_CCFG_MODE_CONF_1_XOSC_MAX_START             0x10       // 1600us
#endif

//#####################################
// Power settings
//#####################################

#ifndef SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA
#define SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA        0xF        // Signed delta value +1 to apply to the VDDR_TRIM_SLEEP target (0xF=-1=default=no compensation)
#endif

#ifndef SET_CCFG_MODE_CONF_DCDC_RECHARGE
#define SET_CCFG_MODE_CONF_DCDC_RECHARGE                0x0        // Use the DC/DC during recharge in powerdown
// #define SET_CCFG_MODE_CONF_DCDC_RECHARGE             0x1        // Do not use the DC/DC during recharge in powerdown
#endif

#ifndef SET_CCFG_MODE_CONF_DCDC_ACTIVE
#define SET_CCFG_MODE_CONF_DCDC_ACTIVE                  0x0        // Use the DC/DC during active mode
// #define SET_CCFG_MODE_CONF_DCDC_ACTIVE               0x1        // Do not use the DC/DC during active mode
#endif

#if ( CCFG_FORCE_VDDR_HH )
#define SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL               0x1        // Special setting to enable forced VDDR HH voltage
#else
#ifndef SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL
// #define SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL            0x0        // VDDS BOD level is 2.0V
#define SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL               0x1        // VDDS BOD level is 1.8V (or 1.65V for external regulator mode)
#endif
#endif

#ifndef SET_CCFG_MODE_CONF_VDDR_CAP
#define SET_CCFG_MODE_CONF_VDDR_CAP                     0x3A       // Unsigned 8-bit integer representing the min. decoupling capacitance on VDDR in units of 100nF
#endif

#ifndef SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC
#define SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC           0x1        // Temperature compensation on VDDR sleep trim disabled (default)
// #define SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC        0x0        // Temperature compensation on VDDR sleep trim enabled
#endif

//#####################################
// Clock settings
//#####################################

#ifndef SET_CCFG_MODE_CONF_SCLK_LF_OPTION
// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x0        // LF clock derived from HF clock. Note: using this configuration will block the device from entering Standby mode.
// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x1        // External LF clock
#define SET_CCFG_MODE_CONF_SCLK_LF_OPTION               0x2        // LF XOSC
// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x3        // LF RCOSC
#endif

#ifndef SET_CCFG_MODE_CONF_XOSC_CAP_MOD
// #define SET_CCFG_MODE_CONF_XOSC_CAP_MOD              0x0        // Apply cap-array delta
#define SET_CCFG_MODE_CONF_XOSC_CAP_MOD                 0x1        // Don't apply cap-array delta
#endif

#ifndef SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA
#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA          0xFF       // Signed 8-bit value, directly modifying trimmed XOSC cap-array value
#endif

#ifndef SET_CCFG_EXT_LF_CLK_DIO
#define SET_CCFG_EXT_LF_CLK_DIO                         0x01       // DIO number if using external LF clock
#endif

#ifndef SET_CCFG_EXT_LF_CLK_RTC_INCREMENT
#define SET_CCFG_EXT_LF_CLK_RTC_INCREMENT               0x800000   // RTC increment representing the external LF clock frequency
#endif

//#####################################
// Special HF clock source setting
//#####################################
#ifndef SET_CCFG_MODE_CONF_XOSC_FREQ
// #define SET_CCFG_MODE_CONF_XOSC_FREQ                 0x0        // HF source is 48 MHz TCXO
// #define SET_CCFG_MODE_CONF_XOSC_FREQ                 0x1        // HF source is HPOSC (BAW) (only valid for CC2652RB)
#define SET_CCFG_MODE_CONF_XOSC_FREQ                    0x2        // HF source is a 48 MHz xtal
// #define SET_CCFG_MODE_CONF_XOSC_FREQ                 0x3        // HF source is a 24 MHz xtal (not supported)
#endif

//#####################################
// Bootloader settings
//#####################################

#ifndef SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE
#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE            0x00       // Disable ROM boot loader
// #define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE         0xC5       // Enable ROM boot loader
#endif

#ifndef SET_CCFG_BL_CONFIG_BL_LEVEL
// #define SET_CCFG_BL_CONFIG_BL_LEVEL                  0x0        // Active low to open boot loader backdoor
#define SET_CCFG_BL_CONFIG_BL_LEVEL                     0x1        // Active high to open boot loader backdoor
#endif

#ifndef SET_CCFG_BL_CONFIG_BL_PIN_NUMBER
#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER                0xFF       // DIO number for boot loader backdoor
#endif

#ifndef SET_CCFG_BL_CONFIG_BL_ENABLE
// #define SET_CCFG_BL_CONFIG_BL_ENABLE                 0xC5       // Enabled boot loader backdoor
#define SET_CCFG_BL_CONFIG_BL_ENABLE                    0xFF       // Disabled boot loader backdoor
#endif

//#####################################
// Debug access settings
//#####################################

#ifndef SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE
#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE           0x00       // Disable unlocking of TI FA option.
// #define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE        0xC5       // Enable unlocking of TI FA option with the unlock code
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE
// #define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE       0x00       // Access disabled
#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE          0xC5       // Access enabled if also enabled in FCFG
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE
//#define SET_CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE    0x00       // Access disabled
#define SET_CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE      0xC5       // Access enabled if also enabled in FCFG
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE
#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE         0x00       // Access disabled
//#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE       0xC5       // Access enabled if also enabled in FCFG
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE
#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE       0x00       // Access disabled
// #define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE    0xC5       // Access enabled if also enabled in FCFG
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE
#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE       0x00       // Access disabled
// #define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE    0xC5       // Access enabled if also enabled in FCFG
#endif

#ifndef SET_CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE
#define SET_CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE          0x00       // Access disabled
// #define SET_CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE       0xC5       // Access enabled if also enabled in FCFG
#endif

//#####################################
// Alternative IEEE 802.15.4 MAC address
//#####################################
#ifndef SET_CCFG_IEEE_MAC_0
#define SET_CCFG_IEEE_MAC_0                             0xFFFFFFFF // Bits [31:0]
#endif

#ifndef SET_CCFG_IEEE_MAC_1
#define SET_CCFG_IEEE_MAC_1                             0xFFFFFFFF // Bits [63:32]
#endif

//#####################################
// Alternative BLE address
//#####################################
#ifndef SET_CCFG_IEEE_BLE_0
#define SET_CCFG_IEEE_BLE_0                             0xFFFFFFFF // Bits [31:0]
#endif

#ifndef SET_CCFG_IEEE_BLE_1
#define SET_CCFG_IEEE_BLE_1                             0xFFFFFFFF // Bits [63:32]
#endif

//#####################################
// Flash erase settings
//#####################################

#ifndef SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N
// #define SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N         0x0        // Any chip erase request detected during boot will be ignored
#define SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N            0x1        // Any chip erase request detected during boot will be performed by the boot FW
#endif

#ifndef SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N
// #define SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N         0x0        // Disable the boot loader bank erase function
#define SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N            0x1        // Enable the boot loader bank erase function
#endif

//#####################################
// Flash image valid
//#####################################
#ifndef SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID
#define SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID           0x00000000                  // Flash image vector table is at address 0x00000000 (default)
// #define SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID        <valid_vector_table_addr>   // Flash image vector table is at address <valid_vector_table_addr>
// #define SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID        <invalid_vector_table_addr> // Flash image vector table address is invalid. ROM boot loader is called.
#endif

//#####################################
// Flash sector write protection
//#####################################
#ifndef SET_CCFG_CCFG_PROT_31_0
#define SET_CCFG_CCFG_PROT_31_0                         0xFFFFFFFF
#endif

#ifndef SET_CCFG_CCFG_PROT_63_32
#define SET_CCFG_CCFG_PROT_63_32                        0xFFFFFFFF
#endif

#ifndef SET_CCFG_CCFG_PROT_95_64
#define SET_CCFG_CCFG_PROT_95_64                        0xFFFFFFFF
#endif

#ifndef SET_CCFG_CCFG_PROT_127_96
#define SET_CCFG_CCFG_PROT_127_96                       0xFFFFFFFF
#endif

//#####################################
// Select between cache or GPRAM
//#####################################
#ifndef SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM
// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM        0x0        // Cache is disabled and GPRAM is available at 0x11000000-0x11001FFF
#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM           0x1        // Cache is enabled and GPRAM is disabled (unavailable)
#endif

//#####################################
// TCXO settings
//#####################################
#ifndef SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO
#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO            0x1        // Deprecated. Must be set to 0x1.
#endif

#ifndef SET_CCFG_MODE_CONF_1_TCXO_TYPE
#define SET_CCFG_MODE_CONF_1_TCXO_TYPE                  0x1        // 1 = Clipped-sine type.
//#define SET_CCFG_MODE_CONF_1_TCXO_TYPE                0x0        // 0 = CMOS type.
#endif

#ifndef SET_CCFG_MODE_CONF_1_TCXO_MAX_START
#define SET_CCFG_MODE_CONF_1_TCXO_MAX_START             0x7F       // Maximum TCXO startup time in units of 100us.
#endif

//*****************************************************************************
// CCFG values that should not be modified.
//*****************************************************************************
#define SET_CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG        0x0058
#define SET_CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS       (CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_M >> CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_S)

#if ( CCFG_FORCE_VDDR_HH )
#define SET_CCFG_MODE_CONF_VDDR_EXT_LOAD                0x0        // Special setting to enable forced VDDR HH voltage
#else
#define SET_CCFG_MODE_CONF_VDDR_EXT_LOAD                0x1
#endif

#define SET_CCFG_MODE_CONF_RTC_COMP                     0x1
#define SET_CCFG_MODE_CONF_HF_COMP                      0x1

#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP45              0xFF
#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP25              0xFF
#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP5               0xFF
#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TM15              0xFF

#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP125             0xFF
#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP105             0xFF
#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP85              0xFF
#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP65              0xFF

#define SET_CCFG_RTC_OFFSET_RTC_COMP_P0                 0xFFFF
#define SET_CCFG_RTC_OFFSET_RTC_COMP_P1                 0xFF
#define SET_CCFG_RTC_OFFSET_RTC_COMP_P2                 0xFF

#define SET_CCFG_FREQ_OFFSET_HF_COMP_P0                 0xFFFF
#define SET_CCFG_FREQ_OFFSET_HF_COMP_P1                 0xFF
#define SET_CCFG_FREQ_OFFSET_HF_COMP_P2                 0xFF

//*****************************************************************************
// Concatenate bit fields to words.
// DO NOT EDIT!
//*****************************************************************************
#define DEFAULT_CCFG_EXT_LF_CLK          ( \
	 ((((uint32_t)( SET_CCFG_EXT_LF_CLK_DIO                          )) << CCFG_EXT_LF_CLK_DIO_S                          ) | ~CCFG_EXT_LF_CLK_DIO_M                          ) & \
	 ((((uint32_t)( SET_CCFG_EXT_LF_CLK_RTC_INCREMENT                )) << CCFG_EXT_LF_CLK_RTC_INCREMENT_S                ) | ~CCFG_EXT_LF_CLK_RTC_INCREMENT_M                ) )

#define DEFAULT_CCFG_MODE_CONF_1         ( \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_TCXO_TYPE                   )) << CCFG_MODE_CONF_1_TCXO_TYPE_S                   ) | ~CCFG_MODE_CONF_1_TCXO_TYPE_M                   ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_TCXO_MAX_START              )) << CCFG_MODE_CONF_1_TCXO_MAX_START_S              ) | ~CCFG_MODE_CONF_1_TCXO_MAX_START_M              ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN               )) << CCFG_MODE_CONF_1_ALT_DCDC_VMIN_S               ) | ~CCFG_MODE_CONF_1_ALT_DCDC_VMIN_M               ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN          )) << CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN_S          ) | ~CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN_M          ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_IPEAK              )) << CCFG_MODE_CONF_1_ALT_DCDC_IPEAK_S              ) | ~CCFG_MODE_CONF_1_ALT_DCDC_IPEAK_M              ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_DELTA_IBIAS_INIT            )) << CCFG_MODE_CONF_1_DELTA_IBIAS_INIT_S            ) | ~CCFG_MODE_CONF_1_DELTA_IBIAS_INIT_M            ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET          )) << CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET_S          ) | ~CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET_M          ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_1_XOSC_MAX_START              )) << CCFG_MODE_CONF_1_XOSC_MAX_START_S              ) | ~CCFG_MODE_CONF_1_XOSC_MAX_START_M              ) )

#define DEFAULT_CCFG_SIZE_AND_DIS_FLAGS  ( \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG         )) << CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG_S         ) | ~CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG_M         ) & \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS        )) << CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_S        ) | ~CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_M        ) & \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO             )) << CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO_S             ) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO_M             ) & \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM            )) << CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM_S            ) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM_M            ) & \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING )) << CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING_S ) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING_M ) & \
	 ((((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR         )) << CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_S         ) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_M         ) )

#define DEFAULT_CCFG_MODE_CONF           ( \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA         )) << CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_S         ) | ~CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_M         ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_DCDC_RECHARGE                 )) << CCFG_MODE_CONF_DCDC_RECHARGE_S                 ) | ~CCFG_MODE_CONF_DCDC_RECHARGE_M                 ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_DCDC_ACTIVE                   )) << CCFG_MODE_CONF_DCDC_ACTIVE_S                   ) | ~CCFG_MODE_CONF_DCDC_ACTIVE_M                   ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_VDDR_EXT_LOAD                 )) << CCFG_MODE_CONF_VDDR_EXT_LOAD_S                 ) | ~CCFG_MODE_CONF_VDDR_EXT_LOAD_M                 ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL                )) << CCFG_MODE_CONF_VDDS_BOD_LEVEL_S                ) | ~CCFG_MODE_CONF_VDDS_BOD_LEVEL_M                ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_SCLK_LF_OPTION                )) << CCFG_MODE_CONF_SCLK_LF_OPTION_S                ) | ~CCFG_MODE_CONF_SCLK_LF_OPTION_M                ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC            )) << CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC_S            ) | ~CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC_M            ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_RTC_COMP                      )) << CCFG_MODE_CONF_RTC_COMP_S                      ) | ~CCFG_MODE_CONF_RTC_COMP_M                      ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_XOSC_FREQ                     )) << CCFG_MODE_CONF_XOSC_FREQ_S                     ) | ~CCFG_MODE_CONF_XOSC_FREQ_M                     ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_XOSC_CAP_MOD                  )) << CCFG_MODE_CONF_XOSC_CAP_MOD_S                  ) | ~CCFG_MODE_CONF_XOSC_CAP_MOD_M                  ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_HF_COMP                       )) << CCFG_MODE_CONF_HF_COMP_S                       ) | ~CCFG_MODE_CONF_HF_COMP_M                       ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA           )) << CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_S           ) | ~CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_M           ) & \
	 ((((uint32_t)( SET_CCFG_MODE_CONF_VDDR_CAP                      )) << CCFG_MODE_CONF_VDDR_CAP_S                      ) | ~CCFG_MODE_CONF_VDDR_CAP_M                      ) )

#define DEFAULT_CCFG_VOLT_LOAD_0         ( \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP45               )) << CCFG_VOLT_LOAD_0_VDDR_EXT_TP45_S               ) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP45_M               ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP25               )) << CCFG_VOLT_LOAD_0_VDDR_EXT_TP25_S               ) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP25_M               ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP5                )) << CCFG_VOLT_LOAD_0_VDDR_EXT_TP5_S                ) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP5_M                ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TM15               )) << CCFG_VOLT_LOAD_0_VDDR_EXT_TM15_S               ) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TM15_M               ) )

#define DEFAULT_CCFG_VOLT_LOAD_1         ( \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP125              )) << CCFG_VOLT_LOAD_1_VDDR_EXT_TP125_S              ) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP125_M              ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP105              )) << CCFG_VOLT_LOAD_1_VDDR_EXT_TP105_S              ) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP105_M              ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP85               )) << CCFG_VOLT_LOAD_1_VDDR_EXT_TP85_S               ) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP85_M               ) & \
	 ((((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP65               )) << CCFG_VOLT_LOAD_1_VDDR_EXT_TP65_S               ) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP65_M               ) )

#define DEFAULT_CCFG_RTC_OFFSET          ( \
	 ((((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P0                  )) << CCFG_RTC_OFFSET_RTC_COMP_P0_S                  ) | ~CCFG_RTC_OFFSET_RTC_COMP_P0_M                  ) & \
	 ((((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P1                  )) << CCFG_RTC_OFFSET_RTC_COMP_P1_S                  ) | ~CCFG_RTC_OFFSET_RTC_COMP_P1_M                  ) & \
	 ((((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P2                  )) << CCFG_RTC_OFFSET_RTC_COMP_P2_S                  ) | ~CCFG_RTC_OFFSET_RTC_COMP_P2_M                  ) )

#define DEFAULT_CCFG_FREQ_OFFSET         ( \
	 ((((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P0                  )) << CCFG_FREQ_OFFSET_HF_COMP_P0_S                  ) | ~CCFG_FREQ_OFFSET_HF_COMP_P0_M                  ) & \
	 ((((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P1                  )) << CCFG_FREQ_OFFSET_HF_COMP_P1_S                  ) | ~CCFG_FREQ_OFFSET_HF_COMP_P1_M                  ) & \
	 ((((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P2                  )) << CCFG_FREQ_OFFSET_HF_COMP_P2_S                  ) | ~CCFG_FREQ_OFFSET_HF_COMP_P2_M                  ) )

#define DEFAULT_CCFG_IEEE_MAC_0          SET_CCFG_IEEE_MAC_0
#define DEFAULT_CCFG_IEEE_MAC_1          SET_CCFG_IEEE_MAC_1
#define DEFAULT_CCFG_IEEE_BLE_0          SET_CCFG_IEEE_BLE_0
#define DEFAULT_CCFG_IEEE_BLE_1          SET_CCFG_IEEE_BLE_1

#define DEFAULT_CCFG_BL_CONFIG           ( \
	 ((((uint32_t)( SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE             )) << CCFG_BL_CONFIG_BOOTLOADER_ENABLE_S             ) | ~CCFG_BL_CONFIG_BOOTLOADER_ENABLE_M             ) & \
	 ((((uint32_t)( SET_CCFG_BL_CONFIG_BL_LEVEL                      )) << CCFG_BL_CONFIG_BL_LEVEL_S                      ) | ~CCFG_BL_CONFIG_BL_LEVEL_M                      ) & \
	 ((((uint32_t)( SET_CCFG_BL_CONFIG_BL_PIN_NUMBER                 )) << CCFG_BL_CONFIG_BL_PIN_NUMBER_S                 ) | ~CCFG_BL_CONFIG_BL_PIN_NUMBER_M                 ) & \
	 ((((uint32_t)( SET_CCFG_BL_CONFIG_BL_ENABLE                     )) << CCFG_BL_CONFIG_BL_ENABLE_S                     ) | ~CCFG_BL_CONFIG_BL_ENABLE_M                     ) )

#define DEFAULT_CCFG_ERASE_CONF          ( \
	 ((((uint32_t)( SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N             )) << CCFG_ERASE_CONF_CHIP_ERASE_DIS_N_S             ) | ~CCFG_ERASE_CONF_CHIP_ERASE_DIS_N_M             ) & \
	 ((((uint32_t)( SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N             )) << CCFG_ERASE_CONF_BANK_ERASE_DIS_N_S             ) | ~CCFG_ERASE_CONF_BANK_ERASE_DIS_N_M             ) )

#define DEFAULT_CCFG_CCFG_TI_OPTIONS     ( \
	 ((((uint32_t)( SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE            )) << CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE_S            ) | ~CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE_M            ) )

#define DEFAULT_CCFG_CCFG_TAP_DAP_0      ( \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE           )) << CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE_S           ) | ~CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE_M           ) & \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE       )) << CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE_S       ) | ~CCFG_CCFG_TAP_DAP_0_PWRPROF_TAP_ENABLE_M       ) & \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE          )) << CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE_S          ) | ~CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE_M          ) )

#define DEFAULT_CCFG_CCFG_TAP_DAP_1      ( \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE        )) << CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE_S        ) | ~CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE_M        ) & \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE        )) << CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE_S        ) | ~CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE_M        ) & \
	 ((((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE           )) << CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE_S           ) | ~CCFG_CCFG_TAP_DAP_1_AON_TAP_ENABLE_M           ) )

#define DEFAULT_CCFG_IMAGE_VALID_CONF    SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID

#define DEFAULT_CCFG_CCFG_PROT_31_0      SET_CCFG_CCFG_PROT_31_0
#define DEFAULT_CCFG_CCFG_PROT_63_32     SET_CCFG_CCFG_PROT_63_32
#define DEFAULT_CCFG_CCFG_PROT_95_64     SET_CCFG_CCFG_PROT_95_64
#define DEFAULT_CCFG_CCFG_PROT_127_96    SET_CCFG_CCFG_PROT_127_96

//*****************************************************************************
// Customer Configuration Area in Lock Page
//*****************************************************************************
#if defined(__IAR_SYSTEMS_ICC__)
__root const ccfg_t __ccfg @ ".ccfg" =
#elif defined(__TI_COMPILER_VERSION__)
#pragma DATA_SECTION(__ccfg, ".ccfg")
#pragma RETAIN(__ccfg)
const ccfg_t __ccfg =
#else
const ccfg_t __ccfg __attribute__((section(".ccfg"))) __attribute__((used)) =
#endif
{                                     // Mapped to address
    DEFAULT_CCFG_EXT_LF_CLK         , // 0x50003FA8 (0x50003xxx maps to last
    DEFAULT_CCFG_MODE_CONF_1        , // 0x50003FAC  sector in FLASH.
    DEFAULT_CCFG_SIZE_AND_DIS_FLAGS , // 0x50003FB0  Independent of FLASH size)
    DEFAULT_CCFG_MODE_CONF          , // 0x50003FB4
    DEFAULT_CCFG_VOLT_LOAD_0        , // 0x50003FB8
    DEFAULT_CCFG_VOLT_LOAD_1        , // 0x50003FBC
    DEFAULT_CCFG_RTC_OFFSET         , // 0x50003FC0
    DEFAULT_CCFG_FREQ_OFFSET        , // 0x50003FC4
    DEFAULT_CCFG_IEEE_MAC_0         , // 0x50003FC8
    DEFAULT_CCFG_IEEE_MAC_1         , // 0x50003FCC
    DEFAULT_CCFG_IEEE_BLE_0         , // 0x50003FD0
    DEFAULT_CCFG_IEEE_BLE_1         , // 0x50003FD4
    DEFAULT_CCFG_BL_CONFIG          , // 0x50003FD8
    DEFAULT_CCFG_ERASE_CONF         , // 0x50003FDC
    DEFAULT_CCFG_CCFG_TI_OPTIONS    , // 0x50003FE0
    DEFAULT_CCFG_CCFG_TAP_DAP_0     , // 0x50003FE4
    DEFAULT_CCFG_CCFG_TAP_DAP_1     , // 0x50003FE8
    DEFAULT_CCFG_IMAGE_VALID_CONF   , // 0x50003FEC
    DEFAULT_CCFG_CCFG_PROT_31_0     , // 0x50003FF0
    DEFAULT_CCFG_CCFG_PROT_63_32    , // 0x50003FF4
    DEFAULT_CCFG_CCFG_PROT_95_64    , // 0x50003FF8
    DEFAULT_CCFG_CCFG_PROT_127_96   , // 0x50003FFC
};

#endif // __CCFC_C__

Фаза 5: Подключить к сборке Hardware Abstraction Layer (HAL)

С настройками системы определились. Теперь можно накропать небольшое приложение. Путь там будет GPIO, LEDs, SysTick, UART, NoRTOS, CLI.

Примеры по настройке периферии можно взять в SimpleLink SDK, например по этим адресам.

C:\ti\simplelink_cc13xx_cc26xx_sdk_5_40_00_40\examples\nortos\CC26X2R1_LAUNCHXL\drivers\gpiointerrupt

Для микроконтроллеров СС26x2 в качестве HAL выступает папка C:/ti/simplelink_cc13xx_cc26xx_sdk_5_40_00_40. Поэтому надо прописать пути к заголовочным файлам. Также производитель распространяет свой код HAL в виде предварительно скомпилированных бинарных библиотек (*.a файлики). В связи с этим для компоновщика надо прописать пути к библиотекам drivers_cc26x2.a, nortos_cc26x2.a и driverlib.lib

ifneq ($(SIMPLELINK_CC13X2_26X2_SDK_MK_INC),Y)
    SIMPLELINK_CC13X2_26X2_SDK_MK_INC=Y

    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
    $(info Build  $(mkfile_path) )
    OPT += -DHAS_SIMPLELINK_CC13X2_26X2_SDK

    SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR = C:/ti/simplelink_cc13xx_cc26xx_sdk_5_40_00_40
    #@echo $(error SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR= $(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR))
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib/bin
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib/bin/gcc
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/inc
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos
    INCDIR += -I$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos/posix
                                                     
    LIBS += $(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/drivers/lib/gcc/m4f/drivers_cc26x2.a
    LIBS += $(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos/lib/gcc/m4f/nortos_cc26x2.a
    LIBS += $(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib/bin/gcc/driverlib.lib

    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos/lib
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos/lib/gcc
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/kernel/nortos/lib/gcc/m4f
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/drivers/lib
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/drivers/lib/gcc
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/drivers/lib/gcc/m4f
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib
    LIBDIR += -L$(SIMPLELINK_CC13X2_26X2_SDK_INSTALL_DIR)/source/ti/devices/cc13x2_cc26x2/driverlib/bin/gcc
endif

Стоит заметить, что для сборки прошивки для СС2652 вообще не нужен оригинальный CMSIS, несмотря на то, что у микроконтроллера ядро ARM Cortex-M4.

Фаза 6: Написание Makefile(ов)

Самый высокоуровневый Makefile для конкретной сборки может выглядеть так

MK_PATH:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
#@echo $(error MK_PATH=$(MK_PATH))
WORKSPACE_LOC:=$(MK_PATH)../../
INCDIR += -I$(MK_PATH)
INCDIR += -I$(WORKSPACE_LOC)

TARGET=launchpad_bootloader_m

include $(MK_PATH)config.mk

ifeq ($(CLI),Y)
    include $(MK_PATH)cli_config.mk
endif

ifeq ($(DIAG),Y)
    include $(MK_PATH)diag_config.mk
endif

include $(WORKSPACE_LOC)code_base.mk
include $(WORKSPACE_LOC)rules.mk
 

Тут только подключение и передача конфигов (config.mk) для данной конкретной сборки, подключение кодовой базы (code_base.mk) и подключение привил сборки кодовой базы (rules.mk). На самом деле даже этот Makefile файл можно сделать общим. Разными будут только config.mk файлики.

Потом для каждого программного компонента можно составить *.mk файл примерно такой структуры. Код, диагностика, система команд для каждого конкретного программного компонента.


$(info LED_MONO_MK_INC=$(LED_MONO_MK_INC))

ifneq ($(LED_MONO_MK_INC),Y)
    LED_MONO_MK_INC=Y

    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
    $(info Build LED Mono)

    #FLASH_FS_DIR = $(WORKSPACE_LOC)Drivers/flash_fs
    LED_MONO_DIR = $(LED_GENERAL_DIR)/led_mono
    #@echo $(error LED_MONO_DIR=$(LED_MONO_DIR))

    ifneq ($(LED),Y)
        @echo $(error Add General LED driver)
    endif

    INCDIR += -I$(LED_MONO_DIR)
    SOURCES_C += $(LED_MONO_DIR)/led_mono_drv.c

    OPT += -DHAS_LED_MONO
    OPT += -DHAS_LED_MONO_PROC
    MATH=Y

    ifeq ($(DIAG),Y)
        ifeq ($(LED_MONO_DIAG),Y)
            OPT += -DHAS_LED_MONO_DIAG
            SOURCES_C += $(LED_MONO_DIR)/led_mono_diag.c
        endif
    endif

    ifeq ($(CLI),Y)
        ifeq ($(LED_MONO_COMMANDS),Y)
            OPT += -DHAS_LED_MONO_COMMANDS
            SOURCES_C += $(LED_MONO_DIR)/led_mono_commands.c
        endif
    endif
endif

В makefile надо указать какое ядро. Надо создать отдельный cortex_m4.mk файл и определить в нем опции компилятора для определения микропроцессорного ядра

$(info CORTEX_M4_MK_INC=$(CORTEX_M4_MK_INC) )
ifneq ($(CORTEX_M4_MK_INC),Y)
    CORTEX_M4_MK_INC=Y

    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
    $(info Build  $(mkfile_path) )

    CORTEX_M4_DIR = $(WORKSPACE_LOC)core/cortex_m4
    INCDIR += -I$(CORTEX_M4_DIR)
    #@echo $(error CORTEX_M4_DIR=$(CORTEX_M4_DIR))
    MCU=Y
    SOURCES_C += $(CORTEX_M4_DIR)/cortex_m4_driver.c
    ifeq ($(DIAG),Y)
        ifeq ($(CORTEX_M4_DIAG),Y)
            SOURCES_C += $(CORTEX_M4_DIR)/cortex_m4_diag.c
        endif
    endif

    OPT += -DHAS_ARM
    OPT += -DHAS_CORTEX_M4
    OPT += -DHAS_CORTEX_M

    CPU = -mcpu=cortex-m4 -march=armv7e-m
    FPU = -mfpu=fpv4-sp-d16
    # float-abi
    FLOAT-ABI = -mfloat-abi=hard
    
    # mcu
    MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

    ifeq ($(SYSTICK),Y)
        #@echo $(error SYSTICK=$(SYSTICK))
        include $(CORTEX_M4_DIR)/systick/systick.mk
    endif
endif


Также нужен специфичный *.mk файл для микроконтроллера CC2652R1FRGZ

#protection against repeated include as in C preprocessor
$(info CC2652R1FRGZ_MK_INC=$(CC2652R1FRGZ_MK_INC) )
ifneq ($(CC2652R1FRGZ_MK_INC),Y)
    CC2652R1FRGZ_MK_INC=Y
    CC2652R1FRGZ_DIR = $(MCU_DIR)/cc2652r1f

    ifeq ($(CC2652),Y)
        OPT += -DHAS_CC2652
        CC26X2=Y
        OPT += -DDeviceFamily_CC26X2
        OPT += -DHAS_CC26x2
        OPT += -DHAS_CC26X2
        OPT += -DHAS_CC26XX
        OPT += -DCC26XX
        OPT += -DCC26x2
    endif

    ifeq ($(CC2652R1FRGZ),Y)
        OPT += -DCC2652R1F
        OPT += -DHAS_CC2652R1F
        OPT += -DCC2652R1FRGZ
        OPT += -DHAS_CC2652R1FRGZ
    endif

    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
    $(info Build  $(mkfile_path) )

    FIRMWARE_TYPE_SELECTED=N
    BOARD=Y

    MICROCONTROLLER=Y
    CC2652R1FRGZ=Y

    INCDIR += -I$(CC2652R1FRGZ_DIR)

    ifeq ($(BOOTLOADER),Y)
        # link script
        FIRMWARE_TYPE_SELECTED=Y
        LDSCRIPT = $(CC2652R1FRGZ_DIR)/cc26x2r1f.lds
    endif

    ifeq ($(GPIO),Y)
        SOURCES_C += $(CC2652R1FRGZ_DIR)/cc2652R1F.c
    endif

    SOURCES_C += $(CC2652R1FRGZ_DIR)/startup_gcc.c
    SOURCES_C += $(CC2652R1FRGZ_DIR)/ccfg.c
    SOURCES_C += $(CC2652R1FRGZ_DIR)/syscalls.c
    
    ifeq ($(SYSTICK),Y)
        SOURCES_C += $(CC2652R1FRGZ_DIR)/systick_general_config.c
    endif

    MCU_SELECTED=Y
endif

И, конечно же, основной универсальный для всех MCU rules.mk файл с правилами сборки можно написать примерно так:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
$(info Build  $(mkfile_path) )

BUILD_DIR = build

INCDIR := $(subst /cygdrive/c/,C:/, $(INCDIR))
#@echo $(error INCDIR=$(INCDIR))

SOURCES_C := $(subst /cygdrive/c/,C:/, $(SOURCES_C))
#@echo $(error SOURCES_C=$(SOURCES_C))

SOURCES_ASM := $(subst /cygdrive/c/,C:/, $(SOURCES_ASM))
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))

LIBS  := $(subst /cygdrive/c/,C:/, $(LIBS))
LDSCRIPT := $(subst /cygdrive/c/,C:/, $(LDSCRIPT))
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))

include $(WORKSPACE_LOC)/toolchain.mk

# CFLAGS
#https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
FLOAT-ABI = -mfloat-abi=hard

MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

# macros for gcc
#CSTANDARD = -std=c11
CSTANDARD = -std=gnu99

AS_DEFS = 

AS_INCLUDES = 

ifeq ($(DEBUG), Y)
    CFLAGS += -g3 -ggdb -gdwarf-2
    OPT += -O0
else
    OPT += -Os
endif

OPT += -fmessage-length=0
OPT += -fsigned-char
OPT += -fno-common
OPT += -fstack-usage
OPT += -finline-small-functions

#Perform dead code elimination
OPT += -fdce

#Perform dead store elimination
OPT += -fdse

ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

CFLAGS += $(CSTANDARD)
CFLAGS += -Wall
#CFLAGS += -Wformat-overflow=1
CFLAGS += $(MCU) $(OPT) -fdata-sections -ffunction-sections $(INCDIR)  

# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

# libraries
LINKER_FLAGS += -Xlinker --gc-sections 
ifeq ($(MBR), Y)
    LIBS += -lnosys
    LDFLAGS += -specs=nano.specs
else
    LINKER_FLAGS += -u _scanf_float
    LINKER_FLAGS += -u _printf_float
endif

ifeq ($(LIBC), Y)
    LIBS += -lc
endif

ifeq ($(MATH), Y)
    LIBS += -lm 
endif

#@echo $(error LDSCRIPT=$(LDSCRIPT))
LIBDIR = 

LDFLAGS += $(MCU) -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections $(LINKER_FLAGS)

# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

# build the application
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_C:.c=.o)))
vpath %.c $(sort $(dir $(SOURCES_C)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_ASM:.S=.o)))
vpath %.S $(sort $(dir $(SOURCES_ASM)))

$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) 
	$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
	$(AS) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	$(SZ) $@

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@
	
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@	
	
$(BUILD_DIR):
	mkdir $@		

# clean up
clean:
	-rm -fR $(BUILD_DIR)

# dependencies
-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

Прелесть makefile в том, что для инициализации сборки достаточно открыть консоль и набрать make all. Затем, через пару минут в соседней папке появятся артефакты. При этом можно еще сохранить в файл полный лог для анализа, а не разглядывать последние 4 экрана как в CCS.

echo off
cls

make clean 2>&1 | tee clean_log.txt
make  2>&1 | tee build_log.txt

Итак, прошивка собирается.

вот такие получились артефакты: *.bin, *.hex, *.map, *.elf

Фаза 7: Запись прошивки в on-chip NOR Flash память

Записать прошивку в микроконтроллер СС2652 тоже можно из консоли утилитой srfprog.exe. Эта утилита входит в состав программы SmartRF Flash Programmer 2. Обычно после установки утилита srfprog живет по адресу

C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Flash Programmer 2\bin\srfprog.exe

Но если забыли, то всегда можно набрать запрос в Win консоли where srfprog.

Вот этот скрипт загружает прошивку в on-chip NOR Flash память микроконтроллера.

echo off
cls
set project_dir=%~dp0

set FLASH_TOOL=srfprog.exe
set BIN_PATH=%project_dir%build\launchpad_bootloader_m.bin

call %FLASH_TOOL% --list all
call %FLASH_TOOL% --help

call %FLASH_TOOL% --target lsidx(0) --erase all --program --file %BIN_PATH% --address 0

Обычно такой вывод информирует об успешной загрузке бинаря


Texas Instruments SmartRF Flash Programmer 2 v1.8.2-windows
-------------------------------------------------------------------------------

Connected over 2-pin cJTAG.

Reading file: C:\....\code_base_firmware\source\projects\launchpad_bootloader_m\build\launchpad_bootloader_m.bin.
2%le size: 360448 bytes.
Number of assigned pages: 44.
About 34 percent of the file contain assigned code.
Start flash erase ...


OK

Start flash programming ...
100%

OK

Reset target ...

OK

C:\....\code_base_firmware\source\projects\launchpad_bootloader_m>

Однако 80..97% вероятность, что после первой же записи бинаря во flash прошивка где-нибудь зависнет, устройство превратится в тыкву. Причем прошивка зависнет где-то в инициализации, еще до запуска суперцикла. Поэтому надо сразу настроить пошаговую отладку через JTAG.

Фаза 8: Запуск GDB сервера

В качестве GDB сервера у TI выступает утилита gdb_agent_console.exe. Для корректного запуска утилиты gdb_agent_console ей надо передать конфигурационный *.dat файл для настройки конкретного отладчика. В случае с платой LAUNCHXL-CC26X2R1 надо выбрать отладчик XDS110. В очередной раз путем grep(ания) на жестком диске, я наткнулся вот на такой файл CC2652_XDS110_JTAG.dat. Причем *.dat файл оказался в папке пользователя а не в SDK.

# config version=3.5
$ sepk
  pod_drvr=jioxds110.dll
  pod_port=0
  pod_supply=1
  pod_voltage_selection=1
  pod_voltage=3.3
$ /
$ product
  title="Texas Instruments XDS110 USB"
  alias=TI_XDS110_USB
  name=XDS110
$ /
$ uscif
  tdoedge=FALL
  tclk_program=DEFAULT
  tclk_frequency=2.5MHz
  jtag_isolate=disable
$ /
$ dot7
  dts_usage=enable
  dts_type=xds110
  dts_program=emulator
  dts_frequency=1.0MHz
  ts_format=jscan0
  ts_pin_width=all_four
$ /
$ swd
  swd_debug=disabled
  swo_data=aux_uart
$ /
@ icepick_c family=icepick_c irbits=6 drbits=1 subpaths=2
  & subpath_2 address=0 default=no custom=yes force=yes pseudo=no
    @ bypass_0 family=bypass irbits=4 drbits=1
  & subpath_0 address=16 default=no custom=yes force=yes pseudo=no
    @ cs_dap_0 family=cs_dap irbits=4 drbits=1 subpaths=1 identify=0x4BA00477 revision=Legacy systemresetwhileconnected=1
      & subpath_1 type=debug address=0 default=no custom=yes force=yes pseudo=no
        @ cortex_m4_0 family=cortex_mxx irbits=0 drbits=0 identify=0x02000000 traceid=0x0
      & /
  & /
# /

Вот скрипт для запуска GDB сервера.

set GDB_SERVER=C:\ti\ccs_base\common\uscif\gdb_agent_console.exe
set USB_JTAG_CONFIG=%CUR_DIR%\CC2652_XDS110_JTAG.dat

%GDB_SERVER% --help
%GDB_SERVER% %USB_JTAG_CONFIG%

В консоли появляется лог сообщения об ожидании подключения на порте 55000

Вот такой текст вывалится в консоль как только GDB клиент подключится к GDB серверу

Фаза 9: GDB клиент

Для запуска GDB клиента надо открыть Win консоль и запустить утилиту arm-none-eabi-gdb.exe, передав ей путь к *.elf файлу с прошивкой. При этом прошивку надо было предварительно собрать с опцией -g.


cls
set GDB_CLIENT="C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin\arm-none-eabi-gdb.exe"
%GDB_CLIENT% --help
set ELF_FILE=%CUR_DIR%\build\launchpad_bootloader_m.elf
%GDB_CLIENT% --nw %ELF_FILE%

Чтобы подключится к микроконтроллеру надо внутри GDB клиента исполнить команду

target remote localhost:55000

Это нужно для того, чтобы подключиться к локальному порту с номеров 55000. И вот началась пошаговая отладка. Если вы спросите:

какая команда GDB клиента оказывается самой полезной?

, то я бы сказал, что это команда backtrace (bt). Именно команда backtrace покажет вам по какой причине прошивка свалилась в FaultISRHandler().

Попытались прописать в нулевой адрес 28 байт и упали в FaultISRHandler
Попытались прописать в нулевой адрес 28 байт и упали в FaultISRHandler

Вообще все известные полезные GDB команды у меня перечислены тут

https://docs.google.com/spreadsheets/d/1AWD8GsDfaA9dtdsfqgbB1klagou1yrREc1AAK9CRUik/edit#gid=0

Взаимодействие отладочных утилит можно показать вот такой блок-схемой

утилиты и файлы которые участвуют в отладке
утилиты и файлы которые участвуют в отладке

Как понять что прошивка завелась?

Достаточно посмотреть на Heartbeat LED. Если мигает значит суперцикл прошивки вертится. Удалось настроить окружение для разработки артефактов и собрать NoRTOS-прошивку для микроконтроллера СС2652 с GPIO, SysTick, LED, UART, CLI. Вот примерный лог загрузки и отладочная CLI в UART. Отладочная консоль отвечает на команды. Значит прошивка завелась. Успех!

Debug CLI Terminal
Debug CLI Terminal

То что вы сейчас видели (Debug CLI Terminal) это UART‑CLI. Про это есть отдельная хорошая история тут — Почему нам нужен UART‑Shell? (или 23 новые возможности).

Итак, всё вышесказанное можно упаковать в одну ёмкую схему ToolChain(на). Это и есть вся система сборки для СС26×2 на основе ARM GCC. Всё на одном листике.

Вывод

Удалось научиться собирать артефакты для микроконтроллеров компании Texas Instruments CC2652 компилятором ARM GCC непосредственно из Makefile(ов). Это является альтернативным и более классическим способом сборки артефактов по отношению к сборке из GUI-IDE CCS. При этом оказалось, что версионному контролю надо подвергнуть всего-навсего 6 расширений файлов *.с *.h *.lds *.mk *.makefile, *.dat. Сборка из Makefile помогает легко и эффективно масштабировать, мигрировать и конфигурировать общую кодовую базу.

Cловарь

Акроним

Расшифровка

CDT

C/C++ Development Tooling

RAM

random access memory

HAL

Hardware Abstraction Layer

OS

operating system

SRAM

static RAM

RISC

reduced instruction set computer

ARM

Advanced RISC Machines

CMSIS

Cortex Microcontroller Software Interface

SDK

software development kit

GNU

GNU’s Not UNIX

CPU

central processing unit

ROM

Read-only memory

GCC

The GNU Compiler Collection

GDB

The GNU Project Debugger

IDE

Integrated Development Environment

JTAG

Joint Test Action Group

JRE

Java Runtime Environment

CCA

Customer Configuration Area

UNIX

UNiplexed Information Computing System

CCFG

Customer Configuration section

TI

Texas Instruments

FPU

Floating Point Unit

Links

https://developer.arm.com/Tools and Software/GNU Toolchain

https://github.com/wufucious/sensortag-blink/tree/f65459dbc182a7c6e2d356f7de033e93d0b7f05b

https://electrolama.com/radio-docs/flash-ti-flash-prog/

https://wiki.st.com/stm32mpu/wiki/GDB_commands

https://habr.com/ru/companies/unwds/articles/390815/

https://habr.com/ru/articles/430732/

https://habr.com/ru/articles/148169/

https://habr.com/ru/articles/162737/

https://docs.google.com/spreadsheets/d/1AWD8GsDfaA9dtdsfqgbB1klagou1yrREc1AAK9CRUik/edit#gid=0

Контрольные вопросы:

1--Что происходит c микроконтроллером между подачей питания и запуском функции main()?

2--Какие расширения файлов надо подвергать версионному контролю при сборке через GCC и MakeFile?

3--Что является артефактами при сборке прошивки для микроконтроллера? Какие расширения у файлов артефактов?

4--Какой путь проходит код с момента написания до попадания в flash память?

5--Какие доки(спеки) нужны для того, чтобы разрабатывать встраиваемый софт? Назовите минимум 4 дока.

6--Компилятору подали 5 *.с файликов и 20 *.h файликов. Сколько будет *.o файликов?

7--В каких случаях артефакты в *.hex файликах предпочтительнее артефактов в *.bin файликах?

Комментарии (18)


  1. Javian
    12.04.2023 03:43
    +1

    Мне понравилась Energia IDE https://energia.nu/ — функциональный аналог Arduino IDE вместо профессионального Code Composer Studio.
    P.S. а что сейчас с доступностью и ценами в РФ на продукцию TI от MSP430 и т.п.


    1. progchip666
      12.04.2023 03:43

      всё очень плохо. Мы в поисках альтернатив


      1. aabzel Автор
        12.04.2023 03:43
        -1

        Нужен вообще полностью российский 32 бит RISC микроконтроллер с уникальным ядром (не ARM Cortex M). Изготовляемый на территории РФ начиная с выращивания кристалла для кремниевых пластин.

        Потом нужна российская операционная системы для PC, российский компилятор для МК и даже текстовый редактор.

        Тогда только и можно будет говорить про суверенитет.


        1. progchip666
          12.04.2023 03:43
          +2

          Такой суверинитет дорого стоит. Если вы немного подумаете своей головой и прикините объёмы продаж своего полностью российского процессора, учтёте что его невозможно сделать без поддержки государства, а поддержка государства связана с коррупцией, особенно в наших условиях (и коррупция ещё не самое страшное зло) то выяснится что и ядро и даже микроконтроллер сделать то в принципе можно(вопрос за какое время) вот только стоить всё это вместе с собственным производством будет столько, что купить его смогут военные за государственные же деньги. У СССР был СЭВ, не маленькая такая структура и то с треском проиграла гонку когда компьютеры стали персональными. Сегодняшняя система нефтяной трубы такого точно не вытянет.


          1. aabzel Автор
            12.04.2023 03:43
            -1

            Тогда РФ окончательно станет чьей-нибудь колонией


            1. progchip666
              12.04.2023 03:43
              +1

              Китайской? Процесс пошёл.


          1. Javian
            12.04.2023 03:43
            +1

            СССР и СЭВ многое просто копировали или на прямую покупали. Не так уж много надо военным.


            1. progchip666
              12.04.2023 03:43
              +1

              Копировать начали далеко не сразу. Когда "компьютеры были большими", стоили дорого и использовались для научных и статистических расчётов СССР был на уровне паритета. Потом компьютеры стали персональными и на западе они стали доступны даже частникам. Массовость стала быстро расти. А в СССР не было рынка - не было достаточного количества индивидуальных платёжеспособных пользователей из за перекосов ценообразования в том числе. Пришлось всё больше и больше копировать, а значит всё больше отставать...


  1. progchip666
    12.04.2023 03:43

    Спасибо. Интересно, но лично для меня, скорее в качестве пищи для ума, чем практического применения. TI и STM итак имеют очень приличные среды разработки.

    В сегодняшних условиях скорее китайские клоны актуальны, но по ним я так понимаю и информацию гораздо сложнее найти чем по TI


    1. aabzel Автор
      12.04.2023 03:43
      -3

      TI и STM итак имеют очень приличные среды разработки.

      Это они специально для детей делают такие IDE.


    1. aabzel Автор
      12.04.2023 03:43
      -1

      STM итак имеет очень приличные среды разработки.


      У меня есть еще методичка как собирать STM32 из MakeFile. https://habr.com/ru/articles/673522/

      Там всё очень просто.


      1. progchip666
        12.04.2023 03:43
        +2

        В моей практике один раз пришлось лезть в MakeFile, когда бутлоадер делал


        1. aabzel Автор
          12.04.2023 03:43
          -2

          Раз не было нужды в Makefile значит у Вас не было командной работы над одной общей кодовой базой, значит у Вас не было модульности в коде, значит у Вас была одна-две сборки на всё, значит у Вас не было сервера сборки, значит у Вас было тотальное дублирование конфигов, значит у Вас не было никакого DevOps(а).

          Поэтому и не приходилось Вам разбираться с MakeFile.

          Что ж для маленьких Pet-проектов использование IDE может быть и оправдано.


  1. DmitryZlobec
    12.04.2023 03:43
    +3

    До запуска main() должен отрабатывать startup код. Где же найти файл для startup кода?

    Это вроде называется crt0. https://ru.wikipedia.org/wiki/Crt0

    Вообще можно использовать Clion, у них сейчас нормальная поддержка Makefile. Другое дело что он платный.(


    1. aabzel Автор
      12.04.2023 03:43
      +1

      Может в desktop разработке и crt0. Просто в мире микроконтроллеров вендоры чипов обычно называют код до main префиксом statrup_*****.[Sc]


  1. lolikandr
    12.04.2023 03:43
    +1

    1--Что происходит до запуска функции main()?
    Startup code, иногда не отделимый от компилятора, который обнуляет статические и глобальные переменные в стандартных секциях и вызывает их конструкторы.
    2--Какие расширения файлов надо подвергать версионному контролю при сборке через GCC и MakeFile?
    Кратко - всё, что не сгенерируется. И лучше всё же настроить .gitignore, в котором указано то, что не надо.
    3--Что является артефактами при сборке прошивки для микроконтроллера?
    Файлы, которые потом используют для прошивки флэш или для тестов и для отладки.
    4--Какой путь проходит код с момента написания до попадания в flash память?
    Коммит - пуш - чек стиля - юниттесты - препроцессор-компиляция-линковка - выделение бинарника - скачиваемый артефакт - прошивка во флэш.
    5--Какие доки(спеки) нужны для того, чтобы разрабатывать встраиваемый софт? Назовите минимум 4 дока.
    Схема электрическая принципиальная, описание чипа и его периферии, эррата на чип, описание c/c++/asm. Некоторые описания слишком большие и TI разбивает их на эн пдф-файлов.
    6--Компилятору подали 5 *.с файликов и 20 *.h файликов. Сколько будет *.o файликов?
    Обычно 5.
    7--В каких случаях артефакты в *.hex файликах предпочтительнее артефактов в *.bin файликах?
    Зависит от программатора и способа обновления прошивки, особенно если шить напрямую во флэш.


    1. aabzel Автор
      12.04.2023 03:43

      Хорошие ответы! Есть еще полный тест
      https://habr.com/ru/articles/676076/

      там самые адекватные вопросы собраны за 12 лет


    1. aabzel Автор
      12.04.2023 03:43

      .hex лучше .bin так как для .hex не надо отдельно указывать адрес старта прошивки.
      Сколько случаев было когда техники загрузчик в *.bin записывали в область generic, а потом удивлялись почему не работает...