Adding BLE OAD to an Existing Project¶
This section will detail how to add BLE OAD to an existing project. The intention is to start with an unmodified sample app from the SDK that does not currently use OAD, and add OAD to it.
Customers can use this section to add OAD to their existing projects. The example project used to demonstrate these steps will be multi_role. The steps are presented in a generic way such that they should apply to all toolchains. If there is a toolchain specific step it will be called out.
Off-Chip OAD¶
This section will detail how to add off-chip OAD to an existing project.
Project Changes¶
In order to add OAD, certain files and include paths should be added to the project, these are detailed in the list below.
Replace the default linker file with the following:
cc26x2_app_oad_agama.cmd
: For CCScc26xx_app_and_stack_agama_oad.icf
: For IAR
Note
In CCS this means editing the .projectspec
file for the application
and re-importing the project.
Open the projectspec file and replace references to
cc13x2_cc26x2_app.cmd
and replace them with
cc26x2_app_oad_agama.cmd
. Then re-import the project
In IAR, this can be done through the project -> options -> linker options menu.
Add the following to the linker defines:
OAD_IMG_E=1
Add the following define to the
.opt
files:-DMAX_PDU_SIZE=251
Note
This define will control the negotiated block size. Block Size is derived from MTU size, which is derived by the minimum of the local supported PDU size and peer’s supported MTU. See OAD Block Size Rules.
Relocate the TI-RTOS reset vectors:
- Set
m3Hwi.resetVectorAddress = 0x50;
in the application’s.cfg
file. Note: Each application has two of these (debug, release), apply change for both. Replace any previous values in the file.
- Set
Enable memory deletes. Add the following option to the
.cfg
file:/* Allow dynamic creation and deletion */ Defaults.common$.memoryPolicy = Types.DELETE_POLICY;
The following files should be removed from the project:
ccfg_app_ble.c
: The BIM links the CCFG in an OAD system.
Add the following files to the project
oad.c
: OAD profile implementationoad.h
: Public OAD profile API definitioncrc32.c
: CRC32 algorithm and helper functionscrc32.h
: CRC32 public API definitionflash_interface.h
: A flash abstraction layer that abstracts flash operations for on and off-chip OAD.oad_iamge_header.h
: Structure definitions for the OAD image headeroad_image_header_app.c
: Application definition of image header.oad_defines.h
: Common header containing OAD definitionsbim_util.h
: Public API definition of utility functions shared between the BIM and application.bim_util.c
: Implementation of BIM utility functionsflash_interface_ext_rtos_NVS.c
: TI-RTOS NVS driver implementation of flash interface for off-chip OAD.
The following files are only required if the optional revert to factory image feature is required:
mark_switch_factory_img.h
: Public API definition for factory image switch.mark_switch_factory_img.c
: Implementation of factory image switching mechanism.
The following pre-processor include paths should be added to the project.
source/ti
source/ti/ble5stack
Add the OAD image tool post build step to the project.
- See the sample applications within the SDK with OAD enabled
(
project_zero
,simple_peripheral_oad_offchip
) and copy the post build step from there. - Note that the
TOOLS_OAD_DIR
environment variable may not exist for all projects. It can either be added or substituted with a path to the OAD executable. - Also note that some projects do not append their configuration name to their output hex file. If the image tool reports that it cannot find the input file, check the naming.
- See the sample applications within the SDK with OAD enabled
(
Code Changes¶
The following changes need to be performed in the source code of the application
Performing the following changes in the high level application task file.
- Add the required include directives:
#include <profiles/oad/cc26xx/oad.h> #include <ti/common/cc26xx/oad/oad_image_header.h> #include <ti/devices/DeviceFamily.h> #include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
- Add the OAD events to the app’s
*_ALL_EVENTS
macro (be sure to add line breaks as necessary):
OAD_QUEUE_EVT | \ OAD_DL_COMPLETE_EVT)
- Define the connection event end event if it does not exist:
#define OAD_CONN_EVT_END_EVT CONN_EVENT_TO_INDEX(MAX_NUM_BLE_CONNS)
- Add the following static variable declarations:
static uint8_t numPendingMsgs = 0; static oadTargetCBs_t MultiRole_oadCBs = { .pfnOadWrite = MultiRole_processOadWriteCB // Write Callback. };
- Inside the application’s
*_init
function, add the following:
// Open the OAD module and add the OAD service to the application if(OAD_SUCCESS != OAD_open(OAD_DEFAULT_INACTIVITY_TIME)) { // Report Error } else { // Register the OAD callback with the application OAD_register(&MultiRole_oadCBs); }
- Add the OAD event processing in the application’s task function:
// OAD events if(events & OAD_QUEUE_EVT) { // Process the OAD Message Queue uint8_t status = OAD_processQueue(); // If the OAD state machine encountered an error, print it // Return codes can be found in oad_constants.h if(status == OAD_DL_COMPLETE) { // Report status } else if(status == OAD_IMG_ID_TIMEOUT) { // This may be an attack, terminate the link, // Note HCI_DISCONNECT_REMOTE_USER_TERM seems to most closet reason for // termination at this state MAP_GAP_TerminateLinkReq( OAD_getactiveCxnHandle(), HCI_DISCONNECT_REMOTE_USER_TERM); } else if(status != OAD_SUCCESS) { // Report Error } } if(events & OAD_DL_COMPLETE_EVT) { // Register for L2CAP Flow Control Events L2CAP_RegisterFlowCtrlTask(selfEntity); }
- Process L2CAP messages from the stack. This should be added to the
application stack message parser. Most sample applications call this
function
*_processStackMsg
.
case L2CAP_SIGNAL_EVENT: { // Process L2CAP free buffer notification MultiRole_processL2CAPMsg( (l2capSignalEvent_t *)pMsg); break; }
- Make an application level L2CAP handler function as below. Add this function to the foward declarations at the top of the file.
static void MultiRole_processL2CAPMsg(l2capSignalEvent_t *pMsg) { static bool firstRun = TRUE; switch(pMsg->opcode) { case L2CAP_NUM_CTRL_DATA_PKT_EVT: { if(firstRun) { firstRun = false; // We only want to set the numPendingMsgs once numPendingMsgs = MAX_NUM_PDU - pMsg->cmd.numCtrlDataPktEvt.numDataPkt; // Wait the number of connection events HCI_EXT_ConnEventNoticeCmd(OAD_getactiveCxnHandle(), selfEntity, OAD_CONN_EVT_END_EVT); } break; } default: break; } }
- In the application’s ICall message handle add a function to process connection event callbacks:
// Check for BLE stack events first if(pEvt->signature == 0xffff) { // .. // Handle an Incoming OAD reboot MultiRole_processOADReboot(pEvt->event_flag); }
- Define the reboot function as below, be sure to add it to the list of forward declarations:
static void MultiRole_processOADReboot(uint32_t stack_event) { if(stack_event & OAD_CONN_EVT_END_EVT) { // Wait until all pending messages are sent if(numPendingMsgs == 0) { // Reset the system SysCtrlSystemReset(); } numPendingMsgs--; } }
- Add the following code to the
ATT_MTU_UPDATED_EVENT
handler. This should be processed by the application when it receives a messages ofgattMsgEvent_t
from the stack.
OAD_setBlockSize(pMsg->msg.mtuEvt.MTU);
Reset OAD if connection drops
- Add the following code to the
GAP_LINK_TERMINATED_EVENT
handler.
// Cancel the OAD if one is going on // A disconnect forces the peer to re-identify OAD_cancel();
- Add the following code to the
(Optional) Add revert to factory image feature to application:
- Add the following code to
main.c
if(!PIN_getInputValue(Board_BUTTON0)) { markSwitchFactoryImg(); }
- Add the following code to
(Optional) Changing external flash pins:
- The examples will work on the CC26x2 LaunchPad out of the box, but for custom hardware the following is recommended.
- Change the pins for the BIM. See
bsp.h
, change the defines below.
// Board external flash defines #define BSP_IOID_FLASH_CS IOID_20 #define BSP_SPI_MOSI IOID_9 #define BSP_SPI_MISO IOID_8 #define BSP_SPI_CLK_FLASH IOID_10
- Change the following defines to match in the application’s board file.
/* SPI */ #define CC26X2R1_LAUNCHXL_SPI_FLASH_CS IOID_20 #define CC26X2R1_LAUNCHXL_FLASH_CS_ON 0 #define CC26X2R1_LAUNCHXL_FLASH_CS_OFF 1 /* SPI Board */ #define CC26X2R1_LAUNCHXL_SPI0_MISO IOID_8 #define CC26X2R1_LAUNCHXL_SPI0_MOSI IOID_9 #define CC26X2R1_LAUNCHXL_SPI0_CLK IOID_10