This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/CC2640: SPI_transfer locking up with simple read transaction

Part Number: CC2640
Other Parts Discussed in Thread: ADS1293, CC2650, SYSBIOS, CC1350

Tool/software: TI-RTOS

Hello,

I am using a modified version of the simple_peripheral example on a custom board with a CC2640F128RHB processor and a TI ADS1293 chip.  The CC2640 and the ADS1293 are connected via SPI.

Before I did anything with our custom board, I loaded the unmodified LaunchPad version of simple_peripheral and was able to get the board to advertise over BLE and get its MAC address.  After that, I added an RTOS task that would blink a couple of LED's at about one-half hertz.  This I did mainly as a sanity check so I could look at the board and know it was still alive.

At this point I had our custom board blinking lights and advertising over BLE at the same time.  So next I added code that would set up SPI, read one 16-bit word, and then close SPI.  This is where I am now stuck.  I can successfully open and close SPI, but if I try to transfer just one 16-bit word, the transfer hangs.  It doesn't matter if I do the transfer in blocking or callback mode.  In blocking mode the processor hangs, and in callback mode the callback function never executes.  Has anyone else run into something like this?

The TI-RTOS version is 2.20.1.8, and the CC26xx BLE stack is version 2.2.1.18

Below are relevant code snippets that show what I wrote for callback mode.

(1) Here are the GPIO bit definitions:
#define Board_RLED                  IOID_13
#define Board_GLED                  IOID_14
#define Board_LED_ON                0
#define Board_LED_OFF               1
#define Board_SPI0_MISO             IOID_4
#define Board_SPI0_MOSI             IOID_3
#define Board_SPI0_CLK              IOID_2
#define Board_SPI0_CSN              IOID_6
#define Board_SPI_ADS1293_CSB       IOID_6
#define Board_SPI_ADS1293_DRDYB        IOID_11
#define Board_RST_ADS1293            IOID_0

(2) Here is how the bits are defined:
const PIN_Config BoardGpioInitTable[] = {
    Board_RLED   | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW  | PIN_PUSHPULL | PIN_DRVSTR_MAX,         /* LED initially on              */
    Board_GLED   | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,         /* LED initially off             */
    Board_SPI_ADS1293_DRDYB | PIN_INPUT_EN | PIN_PULLUP,                                       /* ADS1293 data ready interrupt pin */
    Board_SPI_ADS1293_CSB | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* ADS1293 chip select    */
    Board_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,      /* SPI master out - slave in */
    Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLUP,                                               /* SPI master in - slave out */
    Board_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,       /* SPI clock */
    Board_RST_ADS1293 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,    /* ADS1293 chip reset    */
    PIN_TERMINATE
};

(3) Here is the code.  The call to SPI_init() isn't shown, but it is invoked just before ADS1293_init()
SPI_Params params;
SPI_Handle handle = {0};
SPI_Transaction transaction = {0};
uint16_t txBuf[2] = {0x8000, 0};
uint16_t rxBuf[2] = {0};
uint16_t rx = 0xAAAA;
uint16_t tx = 0x5555;
SPI_Status stat;

void ADS1293TransferCallback(SPI_Handle cbHandle,SPI_Transaction *cbTransaction) {
    tx = *((uint16_t *)(cbTransaction->txBuf));
    rx = *((uint16_t *)(cbTransaction->rxBuf));
    stat = cbTransaction->status;
}

void ADS1293_init() {
    SPI_Params_init(&params);
    params.transferMode = SPI_MODE_CALLBACK;
    params.transferCallbackFxn = ADS1293TransferCallback;
    params.bitRate = 1000000;
    params.frameFormat = SPI_POL1_PHA0;
    params.dataSize = 16;
    params.mode = SPI_MASTER;

    transaction.count = 1;
    transaction.txBuf = txBuf;
    transaction.rxBuf = rxBuf;

    handle = SPI_open(0,&params);
    if (handle != NULL) {
        SPI_transfer(handle,&transaction);
        SPI_close(handle);
    }
}

  • Hi Michael McCully,
    Why do you SPI_close(handle) after SPI_transfer? You use Callback mode in SPI transfer. If you call SPI_close after SPI_transfer, that means you can stop spi before data on spi is transfered successfully. You can try to use the polling mode
  • Hi Vy Luu,

    Thank you for pointing out my error. Of course I cannot call SPI_close() before my callback routine executes After deleting the SPI_close() call, the callback routine now successfully executes every time.

    However, blocking mode still does not work. If I try to perform only one 16-bit SPI_transfer() call in blocking mode (params.transferMode = SPI_MODE_BLOCKING), then the call to SPI_transfer() never returns. I even probed the SPI I/O lines with a scope, and all of them looked OK--16 clocks on SCLK for the 16-bit transfer, etc. But even though the scope traces look OK, SPI_transfer() never returns. Below is my code for ADS1293_init() for blocking mode.

    void ADS1293_init() {
    SPI_Params_init(&params);
    params.transferMode = SPI_MODE_BLOCKING;
    params.bitRate = 1000000;
    params.frameFormat = SPI_POL1_PHA0;
    params.dataSize = 16;
    params.mode = SPI_MASTER;

    transaction.count = 1;
    transaction.txBuf = txBuf;
    transaction.rxBuf = rxBuf;

    handle = SPI_open(0,&params);
    if (handle != NULL) {
    SPI_transfer(handle,&transaction);
    }
    }

    Thanks,
    Mike
  • Hi Michael McCully,
    I dont find any problem in your code.
    1/ You can try to remove the optimize option in compiler and check again
    2/ You can debug in SPICC26XXDMA.c of TI Lib to check the problem. You should check the parameter of object in SPICC26XXDMA_transfer such as:
    frameSize = SPICC26XXDMA_16bit
    datasize = 16
  • Hi Vy Luu,

    I checked everything you suggested.  Removing all compiler optimization did not change the code's behavior, and I found nothing wrong in SPICC26XXDMA.c.  I also tried increasing the stack size in the linker, in case there was an unreported stack overflow, but that also did not change anything.  Next, I may just try bit-banging the SPI pins just to be sure the slave SPI chip is OK.

    However, even if the slave chip is not functioning, the CC2640 SPI should not be locking up.

    Thank you for the suggestions.

    Best Regards,

    Mike

  • Hi Michael McCully,
    Do you check the step by step in SPICC26XXDMA_transfer to find where SPI is blocked? And try to control CS through hal gpio.
  • Hi Vy Luu,

    I tried controlling CS using GPIO calls before I made my first post, and using GPIO calls did not prevent the lockup.

    Below is a partial screen shot from the CCS debugger that shows where the program locks up.  It is on line 864 when the call is made to Semaphore_pend().  You will notice that the parameter list of Semaphore_pend() has a call in it to Semaphore_handle().  The lockup does NOT occur in Semaphore_handle(), because I was able to step through that call with the debugger.  Then, after Semaphore_handle() returned I tried to step into Semaphore_pend(), and when I did that the debugger did not take me into Semaphore_pend().  I had to press either "Terminate" or "Pause" for control to be returned to the debugger, so the lockup occurs somewhere in Semaphore_pend().

    Here is the screen shot.

    Thanks,

    Mike

  • Hi Michael McCully,
    You can set the timeout for transferTimeout in setting of SPI. However, it is not the best way.
    Do you try to set Board_SPI1_CSN to PIN_UNASSIGNED and control CS by the PIN.h?
    Do you make sure about the size of txBuf and rxBuf? Is it uint16_t?
  • Hi Vy Luu,

    I tried all of the things you asked and had no success with them. These things are not shown in my code above, but I tried them all before I made my first post.

    Here are the details:

    (1) When I called SPI_open(), I set SPI_Params::transferTimeout to 1000, and the timeout never occurred. With my system tick value of 10us, the timeout should have occurred in 10ms, but it never did. SPI_transfer() never returned.

    (2) I also tried setting the timeout value to 1 just to see what would happen. In this case, SPI_transfer() also never returned.

    (3) I used the SPI0 peripheral for SPI transfer, and when I was controlling CS in software, yes I did set SPI0_CSN to PIN_UNASSIGNED.

    (4) You can look at my first post and see what I did for callback mode. I did the same thing for blocking mode. Here are the data declarations along with the code from my first post:

    -------------------------------------------------
    uint16_t txBuf[2] = {0x8000, 0};
    uint16_t rxBuf[2] = {0};
    .
    .
    .
    transaction.count = 1;
    transaction.txBuf = txBuf;
    transaction.rxBuf = rxBuf;
    -------------------------------------------------

    Since the buffers are arrays of two uint16_t elements, the transaction dataSize is 16 bits, and the transaction count is one, then there should have been no memory access violation.

    Again, thank you for taking the time to look at this.

    Best Regards,
    Mike
  • Hi Michael McCully,
    Do you capture the wave of SPI signal on Logic analyzer?
    and you send your code file?
    + board.c/h
    + simple_peripheral.c
  • Hi Vy Luu,

    I did not capture the SPI signals on a logic analyzer. What I have is a two-channel oscilloscope, and although I cannot look at all four channels at the same time, I can tell you that the SCK, SDO, SDI, and CS signals are correct when I look at one signal relative to one of the other signals.

    Here are the *board*.h/c and simple_peripheral.c files you requested:

    (1) board.h *****************************************************************************
    /*
    * Copyright (c) 2015-2016, Texas Instruments Incorporated
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the distribution.
    *
    * * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

    #ifndef __BOARD_H
    #define __BOARD_H

    #ifdef __cplusplus
    extern "C" {
    #endif

    #include <ti/drivers/Power.h>

    #include "CC2650_LAUNCHXL.h"

    /* These #defines allow us to reuse TI-RTOS across other device families */
    #define Board_LED0 Board_RLED
    #define Board_LED1 Board_GLED
    #define Board_LED2 Board_LED0

    #define Board_BUTTON0 Board_BTN1
    #define Board_BUTTON1 Board_BTN2

    #define Board_UART0 Board_UART
    #define Board_AES0 Board_AES
    #define Board_WATCHDOG0 Board_WATCHDOG

    #define Board_ADC0 CC2650_LAUNCHXL_ADCVSS
    #define Board_ADC1 CC2650_LAUNCHXL_ADCVDDS

    #define Board_ADCBuf0 CC2650_LAUNCHXL_ADCBuf0
    #define Board_ADCBufChannel0 (0)
    #define Board_ADCBufChannel1 (1)

    #define Board_initGeneral() { \
    Power_init(); \
    if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \
    {System_abort("Error with PIN_init\n"); \
    } \
    }

    #define Board_initGPIO()
    #define Board_initPWM() PWM_init()
    #define Board_initSPI() SPI_init()
    #define Board_initUART() UART_init()
    #define Board_initWatchdog() Watchdog_init()
    #define Board_initADCBuf() ADCBuf_init()
    #define Board_initADC() ADC_init()
    #define GPIO_toggle(n)
    #define GPIO_write(n,m)

    #ifdef __cplusplus
    }
    #endif

    #endif /* __BOARD_H */
    ****************************************************************************************

    (2) CC2650_LAUNCHXL.h ****************************************************************
    /*
    * Copyright (c) 2015-2016, Texas Instruments Incorporated
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the distribution.
    *
    * * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */
    /** ============================================================================
    * @file CC2650_LAUNCHXL.h
    *
    * @brief CC2650 LaunchPad Board Specific header file.
    *
    * NB! This is the board file for CC2650 LaunchPad PCB version 1.1
    *
    * ============================================================================
    */
    #ifndef __CC2650_LAUNCHXL_BOARD_H__
    #define __CC2650_LAUNCHXL_BOARD_H__

    #ifdef __cplusplus
    extern "C" {
    #endif

    /** ============================================================================
    * Includes
    * ==========================================================================*/
    #include <ti/drivers/PIN.h>
    #include <driverlib/ioc.h>

    /** ============================================================================
    * Externs
    * ==========================================================================*/
    extern const PIN_Config BoardGpioInitTable[];

    /** ============================================================================
    * Defines
    * ==========================================================================*/

    /* Same RF Configuration as 7x7 EM */
    #define CC2650EM_7ID

    /* Mapping of pins to board signals using general board aliases
    * <board signal alias> <pin mapping>
    */

    /* Discrete outputs */
    #define Board_RLED IOID_13
    #define Board_GLED IOID_14
    #define Board_LED_ON 0
    #define Board_LED_OFF 1

    /* Discrete inputs */
    #define Board_BTN1 IOID_1
    #define Board_BTN2 PIN_UNASSIGNED

    /* UART Board */
    #define Board_UART_RX PIN_UNASSIGNED
    #define Board_UART_TX PIN_UNASSIGNED
    #define Board_UART_CTS PIN_UNASSIGNED
    #define Board_UART_RTS PIN_UNASSIGNED

    /* SPI Board */
    #define Board_SPI0_MISO IOID_4
    #define Board_SPI0_MOSI IOID_3
    #define Board_SPI0_CLK IOID_2
    #define Board_SPI0_CSN IOID_6
    #define Board_SPI_ADS1293_CSB IOID_6
    #define Board_SPI_ADS1293_DRDYB IOID_11
    #define Board_RST_ADS1293 IOID_0
    #define Board_SPI1_MISO PIN_UNASSIGNED
    #define Board_SPI1_MOSI PIN_UNASSIGNED
    #define Board_SPI1_CLK PIN_UNASSIGNED
    #define Board_SPI1_CSN PIN_UNASSIGNED

    /* I2C */
    #define Board_I2C0_SCL0 IOID_7
    #define Board_I2C0_SDA0 IOID_8

    /* SPI */
    #define Board_SPI_FLASH_CS PIN_UNASSIGNED
    #define Board_FLASH_CS_ON 0
    #define Board_FLASH_CS_OFF 1

    /* Booster pack generic */
    #define Board_DIO0 PIN_UNASSIGNED
    #define Board_DIO1_RFSW PIN_UNASSIGNED
    #define Board_DIO12 PIN_UNASSIGNED
    #define Board_DIO15 PIN_UNASSIGNED
    #define Board_DIO16_TDO PIN_UNASSIGNED
    #define Board_DIO17_TDI PIN_UNASSIGNED
    #define Board_DIO21 PIN_UNASSIGNED
    #define Board_DIO22 PIN_UNASSIGNED

    #define Board_DIO23_ANALOG PIN_UNASSIGNED
    #define Board_DIO24_ANALOG PIN_UNASSIGNED
    #define Board_DIO25_ANALOG PIN_UNASSIGNED
    #define Board_DIO26_ANALOG PIN_UNASSIGNED
    #define Board_DIO27_ANALOG PIN_UNASSIGNED
    #define Board_DIO28_ANALOG PIN_UNASSIGNED
    #define Board_DIO29_ANALOG PIN_UNASSIGNED
    #define Board_DIO30_ANALOG PIN_UNASSIGNED

    /* Booster pack LCD (430BOOST - Sharp96 Rev 1.1) */
    #define Board_LCD_CS PIN_UNASSIGNED
    #define Board_LCD_EXTCOMIN PIN_UNASSIGNED
    #define Board_LCD_ENABLE PIN_UNASSIGNED
    #define Board_LCD_POWER PIN_UNASSIGNED
    #define Board_LCD_CS_ON 1
    #define Board_LCD_CS_OFF 0

    /* PWM outputs */
    #define Board_PWMPIN0 PIN_UNASSIGNED
    #define Board_PWMPIN1 PIN_UNASSIGNED
    #define Board_PWMPIN2 PIN_UNASSIGNED
    #define Board_PWMPIN3 PIN_UNASSIGNED
    #define Board_PWMPIN4 PIN_UNASSIGNED
    #define Board_PWMPIN5 PIN_UNASSIGNED
    #define Board_PWMPIN6 PIN_UNASSIGNED
    #define Board_PWMPIN7 PIN_UNASSIGNED

    /** ============================================================================
    * Instance identifiers
    * ==========================================================================*/
    /* Generic I2C instance identifiers */
    #define Board_I2C CC2650_LAUNCHXL_I2C0
    /* Generic SPI instance identifiers */
    #define Board_SPI0 CC2650_LAUNCHXL_SPI0
    #define Board_SPI1 CC2650_LAUNCHXL_SPI1
    /* Generic UART instance identifiers */
    #define Board_UART CC2650_LAUNCHXL_UART0
    /* Generic Crypto instance identifiers */
    #define Board_CRYPTO CC2650_LAUNCHXL_CRYPTO0
    /* Generic GPTimer instance identifiers */
    #define Board_GPTIMER0A CC2650_LAUNCHXL_GPTIMER0A
    #define Board_GPTIMER0B CC2650_LAUNCHXL_GPTIMER0B
    #define Board_GPTIMER1A CC2650_LAUNCHXL_GPTIMER1A
    #define Board_GPTIMER1B CC2650_LAUNCHXL_GPTIMER1B
    #define Board_GPTIMER2A CC2650_LAUNCHXL_GPTIMER2A
    #define Board_GPTIMER2B CC2650_LAUNCHXL_GPTIMER2B
    #define Board_GPTIMER3A CC2650_LAUNCHXL_GPTIMER3A
    #define Board_GPTIMER3B CC2650_LAUNCHXL_GPTIMER3B
    /* Generic PWM instance identifiers */
    #define Board_PWM0 CC2650_LAUNCHXL_PWM0
    #define Board_PWM1 CC2650_LAUNCHXL_PWM1
    #define Board_PWM2 CC2650_LAUNCHXL_PWM2
    #define Board_PWM3 CC2650_LAUNCHXL_PWM3
    #define Board_PWM4 CC2650_LAUNCHXL_PWM4
    #define Board_PWM5 CC2650_LAUNCHXL_PWM5
    #define Board_PWM6 CC2650_LAUNCHXL_PWM6
    #define Board_PWM7 CC2650_LAUNCHXL_PWM7

    /** ============================================================================
    * Number of peripherals and their names
    * ==========================================================================*/

    /*!
    * @def CC2650_LAUNCHXL_I2CName
    * @brief Enum of I2C names on the CC2650 dev board
    */
    typedef enum CC2650_LAUNCHXL_I2CName {
    CC2650_LAUNCHXL_I2C0 = 0,

    CC2650_LAUNCHXL_I2CCOUNT
    } CC2650_LAUNCHXL_I2CName;

    /*!
    * @def CC2650_LAUNCHXL_CryptoName
    * @brief Enum of Crypto names on the CC2650 dev board
    */
    typedef enum CC2650_LAUNCHXL_CryptoName {
    CC2650_LAUNCHXL_CRYPTO0 = 0,

    CC2650_LAUNCHXL_CRYPTOCOUNT
    } CC2650_LAUNCHXL_CryptoName;


    /*!
    * @def CC2650_LAUNCHXL_SPIName
    * @brief Enum of SPI names on the CC2650 dev board
    */
    typedef enum CC2650_LAUNCHXL_SPIName {
    CC2650_LAUNCHXL_SPI0 = 0,
    CC2650_LAUNCHXL_SPI1,

    CC2650_LAUNCHXL_SPICOUNT
    } CC2650_LAUNCHXL_SPIName;

    /*!
    * @def CC2650_LAUNCHXL_TRNGName
    * @brief Enum of TRNG names on the board
    */
    typedef enum CC2650_LAUNCHXL_TRNGName {
    CC2650_LAUNCHXL_TRNG0 = 0,
    CC2650_LAUNCHXL_TRNGCOUNT
    } CC2650_LAUNCHXL_TRNGName;

    /*!
    * @def CC2650_LAUNCHXL_UARTName
    * @brief Enum of UARTs on the CC2650 dev board
    */
    typedef enum CC2650_LAUNCHXL_UARTName {
    CC2650_LAUNCHXL_UART0 = 0,

    CC2650_LAUNCHXL_UARTCOUNT
    } CC2650_LAUNCHXL_UARTName;

    /*!
    * @def CC2650_LAUNCHXL_UdmaName
    * @brief Enum of DMA buffers
    */
    typedef enum CC2650_LAUNCHXL_UdmaName {
    CC2650_LAUNCHXL_UDMA0 = 0,

    CC2650_LAUNCHXL_UDMACOUNT
    } CC2650_LAUNCHXL_UdmaName;

    /*!
    * @def CC2650_LAUNCHXL_GPTimerName
    * @brief Enum of GPTimer parts
    */
    typedef enum CC2650_LAUNCHXL_GPTimerName
    {
    CC2650_LAUNCHXL_GPTIMER0A = 0,
    CC2650_LAUNCHXL_GPTIMER0B,
    CC2650_LAUNCHXL_GPTIMER1A,
    CC2650_LAUNCHXL_GPTIMER1B,
    CC2650_LAUNCHXL_GPTIMER2A,
    CC2650_LAUNCHXL_GPTIMER2B,
    CC2650_LAUNCHXL_GPTIMER3A,
    CC2650_LAUNCHXL_GPTIMER3B,
    CC2650_LAUNCHXL_GPTIMERPARTSCOUNT
    } CC2650_LAUNCHXL_GPTimerName;

    /*!
    * @def CC2650_LAUNCHXL_GPTimers
    * @brief Enum of GPTimers
    */
    typedef enum CC2650_LAUNCHXL_GPTimers
    {
    CC2650_LAUNCHXL_GPTIMER0 = 0,
    CC2650_LAUNCHXL_GPTIMER1,
    CC2650_LAUNCHXL_GPTIMER2,
    CC2650_LAUNCHXL_GPTIMER3,
    CC2650_LAUNCHXL_GPTIMERCOUNT
    } CC2650_LAUNCHXL_GPTimers;

    /*!
    * @def CC2650_LAUNCHXL_PWM
    * @brief Enum of PWM outputs on the board
    */
    typedef enum CC2650_LAUNCHXL_PWM
    {
    CC2650_LAUNCHXL_PWM0 = 0,
    CC2650_LAUNCHXL_PWM1,
    CC2650_LAUNCHXL_PWM2,
    CC2650_LAUNCHXL_PWM3,
    CC2650_LAUNCHXL_PWM4,
    CC2650_LAUNCHXL_PWM5,
    CC2650_LAUNCHXL_PWM6,
    CC2650_LAUNCHXL_PWM7,
    CC2650_LAUNCHXL_PWMCOUNT
    } CC2650_LAUNCHXL_PWM;

    /*!
    * @def CC2650_LAUNCHXL_ADCBufName
    * @brief Enum of ADCs
    */
    typedef enum CC2650_LAUNCHXL_ADCBufName {
    CC2650_LAUNCHXL_ADCBuf0 = 0,
    CC2650_LAUNCHXL_ADCBufCOUNT
    } CC2650_LAUNCHXL_ADCBufName;


    /*!
    * @def CC2650_LAUNCHXL_ADCName
    * @brief Enum of ADCs
    */
    typedef enum CC2650_LAUNCHXL_ADCName {
    CC2650_LAUNCHXL_ADC0 = 0,
    CC2650_LAUNCHXL_ADC1,
    CC2650_LAUNCHXL_ADC2,
    CC2650_LAUNCHXL_ADC3,
    CC2650_LAUNCHXL_ADC4,
    CC2650_LAUNCHXL_ADC5,
    CC2650_LAUNCHXL_ADC6,
    CC2650_LAUNCHXL_ADC7,
    CC2650_LAUNCHXL_ADCDCOUPL,
    CC2650_LAUNCHXL_ADCVSS,
    CC2650_LAUNCHXL_ADCVDDS,
    CC2650_LAUNCHXL_ADCCOUNT
    } CC2650_LAUNCHXL_ADCName;


    #ifdef __cplusplus
    }
    #endif

    #endif /* __CC2650_LAUNCHXL_BOARD_H__ */
    ****************************************************************************************

    (3) CC2650_LAUNCHXL.c ****************************************************************
    /*
    * Copyright (c) 2016, Texas Instruments Incorporated
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the distribution.
    *
    * * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

    /*
    * ====================== CC2650_LAUNCHXL.c ===================================
    * This file is responsible for setting up the board specific items for the
    * CC2650 LaunchPad.
    */


    /*
    * ====================== Includes ============================================
    */
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>

    #include <ti/sysbios/family/arm/m3/Hwi.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    #include <ti/drivers/PWM.h>
    #include <ti/drivers/pwm/PWMTimerCC26XX.h>
    #include <ti/drivers/timer/GPTimerCC26XX.h>
    #include <ti/drivers/Power.h>
    #include <ti/drivers/power/PowerCC26XX.h>

    #include <inc/hw_memmap.h>
    #include <inc/hw_ints.h>
    #include <driverlib/ioc.h>
    #include <driverlib/udma.h>

    #include "Board.h"

    /*
    * ========================= IO driver initialization =========================
    * From main, PIN_init(BoardGpioInitTable) should be called to setup safe
    * settings for this board.
    * When a pin is allocated and then de-allocated, it will revert to the state
    * configured in this table.
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable")
    #pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs")
    #endif

    const PIN_Config BoardGpioInitTable[] = {
    Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially on */
    Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */
    Board_SPI_ADS1293_DRDYB | PIN_INPUT_EN | PIN_PULLUP, /* ADS1293 data ready interrupt pin */
    Board_SPI_ADS1293_CSB | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* ADS1293 chip select */
    Board_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* SPI master out - slave in */
    Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLUP, /* SPI master in - slave out */
    Board_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* SPI clock */
    Board_RST_ADS1293 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* ADS1293 chip reset */
    PIN_TERMINATE
    };

    const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = {
    .intPriority = ~0,
    .swiPriority = 0
    };
    /*============================================================================*/

    /*
    * ============================= Power begin ==================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config")
    #endif
    const PowerCC26XX_Config PowerCC26XX_config = {
    .policyInitFxn = NULL,
    .policyFxn = &PowerCC26XX_standbyPolicy,
    .calibrateFxn = &PowerCC26XX_calibrate,
    .enablePolicy = TRUE,
    .calibrateRCOSC_LF = TRUE,
    .calibrateRCOSC_HF = TRUE,
    };
    /*
    * ============================= Power end ====================================
    */

    /*
    * ============================= UART begin ===================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(UART_config, ".const:UART_config")
    #pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/UART.h>
    #include <ti/drivers/uart/UARTCC26XX.h>

    /* UART objects */
    UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT];

    /* UART hardware parameter structure, also used to assign UART pins */
    const UARTCC26XX_HWAttrsV1 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = {
    {
    .baseAddr = UART0_BASE,
    .powerMngrId = PowerCC26XX_PERIPH_UART0,
    .intNum = INT_UART0_COMB,
    .intPriority = ~0,
    .swiPriority = 0,
    .txPin = Board_UART_TX,
    .rxPin = Board_UART_RX,
    .ctsPin = PIN_UNASSIGNED,
    .rtsPin = PIN_UNASSIGNED
    }
    };

    /* UART configuration structure */
    const UART_Config UART_config[] = {
    {
    .fxnTablePtr = &UARTCC26XX_fxnTable,
    .object = &uartCC26XXObjects[0],
    .hwAttrs = &uartCC26XXHWAttrs[0]
    },
    {NULL, NULL, NULL}
    };
    /*
    * ============================= UART end =====================================
    */

    /*
    * ============================= UDMA begin ===================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config")
    #pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/dma/UDMACC26XX.h>

    /* UDMA objects */
    UDMACC26XX_Object udmaObjects[CC2650_LAUNCHXL_UDMACOUNT];

    /* UDMA configuration structure */
    const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_LAUNCHXL_UDMACOUNT] = {
    {
    .baseAddr = UDMA0_BASE,
    .powerMngrId = PowerCC26XX_PERIPH_UDMA,
    .intNum = INT_DMA_ERR,
    .intPriority = ~0
    }
    };

    /* UDMA configuration structure */
    const UDMACC26XX_Config UDMACC26XX_config[] = {
    {
    .object = &udmaObjects[0],
    .hwAttrs = &udmaHWAttrs[0]
    },
    {NULL, NULL}
    };
    /*
    * ============================= UDMA end =====================================
    */

    /*
    * ========================== SPI DMA begin ===================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(SPI_config, ".const:SPI_config")
    #pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/spi/SPICC26XXDMA.h>

    /* SPI objects */
    SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT];

    /* SPI configuration structure, describing which pins are to be used */
    const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = {
    {
    .baseAddr = SSI0_BASE,
    .intNum = INT_SSI0_COMB,
    .intPriority = ~0,
    .swiPriority = 0,
    .powerMngrId = PowerCC26XX_PERIPH_SSI0,
    .defaultTxBufValue = 0,
    .rxChannelBitMask = 1<<UDMA_CHAN_SSI0_RX,
    .txChannelBitMask = 1<<UDMA_CHAN_SSI0_TX,
    .mosiPin = Board_SPI0_MOSI,
    .misoPin = Board_SPI0_MISO,
    .clkPin = Board_SPI0_CLK,
    .csnPin = Board_SPI0_CSN
    },
    {
    .baseAddr = SSI1_BASE,
    .intNum = INT_SSI1_COMB,
    .intPriority = ~0,
    .swiPriority = 0,
    .powerMngrId = PowerCC26XX_PERIPH_SSI1,
    .defaultTxBufValue = 0,
    .rxChannelBitMask = 1<<UDMA_CHAN_SSI1_RX,
    .txChannelBitMask = 1<<UDMA_CHAN_SSI1_TX,
    .mosiPin = Board_SPI1_MOSI,
    .misoPin = Board_SPI1_MISO,
    .clkPin = Board_SPI1_CLK,
    .csnPin = Board_SPI1_CSN
    }
    };

    /* SPI configuration structure */
    const SPI_Config SPI_config[] = {
    {
    .fxnTablePtr = &SPICC26XXDMA_fxnTable,
    .object = &spiCC26XXDMAObjects[0],
    .hwAttrs = &spiCC26XXDMAHWAttrs[0]
    },
    {
    .fxnTablePtr = &SPICC26XXDMA_fxnTable,
    .object = &spiCC26XXDMAObjects[1],
    .hwAttrs = &spiCC26XXDMAHWAttrs[1]
    },
    {NULL, NULL, NULL}
    };
    /*
    * ========================== SPI DMA end =====================================
    */


    /*
    * ============================= I2C Begin=====================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(I2C_config, ".const:I2C_config")
    #pragma DATA_SECTION(i2cCC26xxHWAttrs, ".const:i2cCC26xxHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/i2c/I2CCC26XX.h>

    /* I2C objects */
    I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT];

    /* I2C configuration structure, describing which pins are to be used */
    const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = {
    {
    .baseAddr = I2C0_BASE,
    .powerMngrId = PowerCC26XX_PERIPH_I2C0,
    .intNum = INT_I2C_IRQ,
    .intPriority = ~0,
    .swiPriority = 0,
    .sdaPin = Board_I2C0_SDA0,
    .sclPin = Board_I2C0_SCL0,
    }
    };

    /* I2C configuration structure */
    const I2C_Config I2C_config[] = {
    {
    .fxnTablePtr = &I2CCC26XX_fxnTable,
    .object = &i2cCC26xxObjects[0],
    .hwAttrs = &i2cCC26xxHWAttrs[0]
    },
    {NULL, NULL, NULL}
    };
    /*
    * ========================== I2C end =========================================
    */

    /*
    * ========================== Crypto begin ====================================
    * NOTE: The Crypto implementation should be considered experimental
    * and not validated!
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config")
    #pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/crypto/CryptoCC26XX.h>

    /* Crypto objects */
    CryptoCC26XX_Object cryptoCC26XXObjects[CC2650_LAUNCHXL_CRYPTOCOUNT];

    /* Crypto configuration structure, describing which pins are to be used */
    const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTOCOUNT] = {
    {
    .baseAddr = CRYPTO_BASE,
    .powerMngrId = PowerCC26XX_PERIPH_CRYPTO,
    .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ,
    .intPriority = ~0,
    }
    };

    /* Crypto configuration structure */
    const CryptoCC26XX_Config CryptoCC26XX_config[] = {
    {
    .object = &cryptoCC26XXObjects[0],
    .hwAttrs = &cryptoCC26XXHWAttrs[0]
    },
    {NULL, NULL}
    };
    /*
    * ========================== Crypto end ======================================
    */


    /*
    * ========================= RF driver begin ==================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/rf/RF.h>

    /* RF hwi and swi priority */
    const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = {
    .hwiCpe0Priority = ~0,
    .hwiHwPriority = ~0,
    .swiCpe0Priority = 5,
    .swiHwPriority = 5,
    };

    /*
    * ========================== RF driver end ===================================
    */

    /*
    * ========================= Display begin ====================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(Display_config, ".const:Display_config")
    #pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs")
    #pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs")
    #endif

    #include <ti/mw/display/Display.h>
    #include <ti/mw/display/DisplaySharp.h>
    #include <ti/mw/display/DisplayUart.h>

    /* Structures for UartPlain Blocking */
    DisplayUart_Object displayUartObject;

    #ifndef BOARD_DISPLAY_UART_STRBUF_SIZE
    #define BOARD_DISPLAY_UART_STRBUF_SIZE 128
    #endif
    static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE];

    const DisplayUart_HWAttrs displayUartHWAttrs = {
    .uartIdx = Board_UART,
    .baudRate = 115200,
    .mutexTimeout = BIOS_WAIT_FOREVER,
    .strBuf = uartStringBuf,
    .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE,
    };

    /* Structures for SHARP */
    DisplaySharp_Object displaySharpObject;

    #ifndef BOARD_DISPLAY_SHARP_SIZE
    #define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128.
    #endif
    static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8];

    const DisplaySharp_HWAttrs displaySharpHWattrs = {
    .spiIndex = Board_SPI0,
    .csPin = Board_LCD_CS,
    .extcominPin = Board_LCD_EXTCOMIN,
    .powerPin = Board_LCD_POWER,
    .enablePin = Board_LCD_ENABLE,
    .pixelWidth = BOARD_DISPLAY_SHARP_SIZE,
    .pixelHeight = BOARD_DISPLAY_SHARP_SIZE,
    .displayBuf = sharpDisplayBuf,
    };

    /* Array of displays */
    const Display_Config Display_config[] = {
    #if !defined(BOARD_DISPLAY_EXCLUDE_UART)
    {
    .fxnTablePtr = &DisplayUart_fxnTable,
    .object = &displayUartObject,
    .hwAttrs = &displayUartHWAttrs,
    },
    #endif
    #if !defined(BOARD_DISPLAY_EXCLUDE_LCD)
    {
    .fxnTablePtr = &DisplaySharp_fxnTable,
    .object = &displaySharpObject,
    .hwAttrs = &displaySharpHWattrs
    },
    #endif
    { NULL, NULL, NULL } // Terminator
    };

    /*
    * ========================= Display end ======================================
    */

    /*
    * ============================ GPTimer begin =================================
    * Remove unused entries to reduce flash usage both in Board.c and Board.h
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config")
    #pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs")
    #endif

    /* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */
    const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = {
    { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, },
    { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, },
    { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, },
    { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, },
    { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, },
    { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, },
    { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, },
    { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, },
    };

    /* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */
    GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMERCOUNT];

    /* GPTimer configuration (used as GPTimer_Handle by driver and application) */
    const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = {
    { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A },
    { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B },
    { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A },
    { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B },
    { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A },
    { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B },
    { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A },
    { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B },
    };

    /*
    * ============================ GPTimer end ===================================
    */



    /*
    * ============================= PWM begin ====================================
    * Remove unused entries to reduce flash usage both in Board.c and Board.h
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(PWM_config, ".const:PWM_config")
    #pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs")
    #endif

    /* PWM configuration, one per PWM output. */
    PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWMCOUNT] = {
    { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A },
    { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B },
    { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A },
    { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B },
    { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A },
    { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B },
    { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A },
    { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B },
    };

    /* PWM object, one per PWM output */
    PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWMCOUNT];

    extern const PWM_FxnTable PWMTimerCC26XX_fxnTable;

    /* PWM configuration (used as PWM_Handle by driver and application) */
    const PWM_Config PWM_config[CC2650_LAUNCHXL_PWMCOUNT + 1] = {
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] },
    { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] },
    { NULL, NULL, NULL }
    };


    /*
    * ============================= PWM end ======================================
    */

    /*
    * ========================== ADCBuf begin =========================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config")
    #pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs")
    #pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut")
    #endif

    /* Include drivers */
    #include <ti/drivers/ADCBuf.h>
    #include <ti/drivers/adcbuf/ADCBufCC26XX.h>

    /* ADCBuf objects */
    ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBufCOUNT];

    /*
    * This table converts a virtual adc channel into a dio and internal analogue input signal.
    * This table is necessary for the functioning of the adcBuf driver.
    * Comment out unused entries to save flash.
    * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though.
    * The mapping of dio and internal signals is package dependent.
    */
    const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = {
    {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS},
    {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL},
    {PIN_UNASSIGNED, ADC_COMPB_IN_VSS},
    {Board_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7},
    {Board_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6},
    {Board_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5},
    {Board_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4},
    {Board_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3},
    {Board_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2},
    {Board_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1},
    {Board_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0},
    };

    const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBufCOUNT] = {
    {
    .intPriority = ~0,
    .swiPriority = 0,
    .adcChannelLut = ADCBufCC26XX_adcChannelLut,
    .gpTimerUnit = Board_GPTIMER0A,
    .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A,
    }
    };

    const ADCBuf_Config ADCBuf_config[] = {
    {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]},
    {NULL, NULL, NULL},
    };
    /*
    * ========================== ADCBuf end =========================================
    */



    /*
    * ========================== ADC begin =========================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(ADC_config, ".const:ADC_config")
    #pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs")
    #endif

    /* Include drivers */
    #include <ti/drivers/ADC.h>
    #include <ti/drivers/adc/ADCCC26XX.h>

    /* ADC objects */
    ADCCC26XX_Object adcCC26xxObjects[CC2650_LAUNCHXL_ADCCOUNT];


    const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCCOUNT] = {
    {
    .adcDIO = Board_DIO23_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO7,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO24_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO6,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO25_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO5,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO26_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO4,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO27_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO3,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO28_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO2,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO29_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO1,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = Board_DIO30_ANALOG,
    .adcCompBInput = ADC_COMPB_IN_AUXIO0,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = PIN_UNASSIGNED,
    .adcCompBInput = ADC_COMPB_IN_DCOUPL,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = PIN_UNASSIGNED,
    .adcCompBInput = ADC_COMPB_IN_VSS,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    },
    {
    .adcDIO = PIN_UNASSIGNED,
    .adcCompBInput = ADC_COMPB_IN_VDDS,
    .refSource = ADCCC26XX_FIXED_REFERENCE,
    .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
    .inputScalingEnabled = true,
    .triggerSource = ADCCC26XX_TRIGGER_MANUAL
    }
    };

    const ADC_Config ADC_config[] = {
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[4], &adcCC26xxHWAttrs[4]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[5], &adcCC26xxHWAttrs[5]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[6], &adcCC26xxHWAttrs[6]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[7], &adcCC26xxHWAttrs[7]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[8], &adcCC26xxHWAttrs[8]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[9], &adcCC26xxHWAttrs[9]},
    {&ADCCC26XX_fxnTable, &adcCC26xxObjects[10], &adcCC26xxHWAttrs[10]},
    {NULL, NULL, NULL},
    };

    /*
    * ========================== ADC end =========================================
    */

    /*
    * ========================= TRNG begin ====================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(TRNGCC26XX_config, ".const:TRNGCC26XX_config")
    #pragma DATA_SECTION(TRNGCC26XXHWAttrs, ".const:TRNGCC26XXHWAttrs")
    #endif

    /* Include drivers */
    #include <TRNGCC26XX.h>

    /* TRNG objects */
    TRNGCC26XX_Object trngCC26XXObjects[CC2650_LAUNCHXL_TRNGCOUNT];

    /* TRNG configuration structure, describing which pins are to be used */
    const TRNGCC26XX_HWAttrs TRNGCC26XXHWAttrs[CC2650_LAUNCHXL_TRNGCOUNT] = {
    {
    .powerMngrId = PowerCC26XX_PERIPH_TRNG,
    }
    };

    /* TRNG configuration structure */
    const TRNGCC26XX_Config TRNGCC26XX_config[] = {
    {
    .object = &trngCC26XXObjects[0],
    .hwAttrs = &TRNGCC26XXHWAttrs[0]
    },
    {NULL, NULL}
    };

    /*
    * ========================= TRNG end ====================================
    */
    ****************************************************************************************

    (4) simple_peripheral.c *****************************************************************
    /******************************************************************************

    @file simple_peripheral.c

    @brief This file contains the Simple BLE Peripheral sample application for use
    with the CC2650 Bluetooth Low Energy Protocol Stack.

    Group: WCS, BTS
    Target Device: CC2650, CC2640, CC1350

    ******************************************************************************

    Copyright (c) 2013-2016, Texas Instruments Incorporated
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

    * Neither the name of Texas Instruments Incorporated nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    ******************************************************************************
    Release Name: ble_sdk_2_02_01_18
    Release Date: 2016-10-26 15:20:04
    *****************************************************************************/

    /*********************************************************************
    * INCLUDES
    */
    #include <string.h>

    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Queue.h>

    #include "hci_tl.h"
    #include "gatt.h"
    #include "linkdb.h"
    #include "gapgattserver.h"
    #include "gattservapp.h"
    #include "devinfoservice.h"
    #include "simple_gatt_profile.h"

    #if defined(FEATURE_OAD) || defined(IMAGE_INVALIDATE)
    #include "oad_target.h"
    #include "oad.h"
    #endif //FEATURE_OAD || IMAGE_INVALIDATE

    #include "peripheral.h"
    #include "gapbondmgr.h"

    #include "osal_snv.h"
    #include "icall_apimsg.h"

    #include "util.h"

    #ifdef USE_RCOSC
    #include "rcosc_calibration.h"
    #endif //USE_RCOSC

    #include <ti/mw/display/Display.h>
    #include "board_key.h"

    #include "board.h"

    #include "simple_peripheral.h"

    #if defined( USE_FPGA ) || defined( DEBUG_SW_TRACE )
    #include <driverlib/ioc.h>
    #endif // USE_FPGA | DEBUG_SW_TRACE

    /*********************************************************************
    * CONSTANTS
    */

    // Advertising interval when device is discoverable (units of 625us, 160=100ms)
    #define DEFAULT_ADVERTISING_INTERVAL 160

    // Limited discoverable mode advertises for 30.72s, and then stops
    // General discoverable mode advertises indefinitely
    #define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL

    #ifndef FEATURE_OAD
    // Minimum connection interval (units of 1.25ms, 80=100ms) if automatic
    // parameter update request is enabled
    #define DEFAULT_DESIRED_MIN_CONN_INTERVAL 80

    // Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic
    // parameter update request is enabled
    #define DEFAULT_DESIRED_MAX_CONN_INTERVAL 800
    #else //!FEATURE_OAD
    // Minimum connection interval (units of 1.25ms, 8=10ms) if automatic
    // parameter update request is enabled
    #define DEFAULT_DESIRED_MIN_CONN_INTERVAL 8

    // Maximum connection interval (units of 1.25ms, 8=10ms) if automatic
    // parameter update request is enabled
    #define DEFAULT_DESIRED_MAX_CONN_INTERVAL 8
    #endif // FEATURE_OAD

    // Slave latency to use if automatic parameter update request is enabled
    #define DEFAULT_DESIRED_SLAVE_LATENCY 0

    // Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter
    // update request is enabled
    #define DEFAULT_DESIRED_CONN_TIMEOUT 1000

    // Whether to enable automatic parameter update request when a connection is
    // formed
    #define DEFAULT_ENABLE_UPDATE_REQUEST GAPROLE_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS

    // Connection Pause Peripheral time value (in seconds)
    #define DEFAULT_CONN_PAUSE_PERIPHERAL 6

    // How often to perform periodic event (in msec)
    #define SBP_PERIODIC_EVT_PERIOD 5000

    #ifdef FEATURE_OAD
    // The size of an OAD packet.
    #define OAD_PACKET_SIZE ((OAD_BLOCK_SIZE) + 2)
    #endif // FEATURE_OAD

    // Task configuration
    #define SBP_TASK_PRIORITY 1


    #ifndef SBP_TASK_STACK_SIZE
    #define SBP_TASK_STACK_SIZE 644
    #endif

    // Internal Events for RTOS application
    #define SBP_STATE_CHANGE_EVT 0x0001
    #define SBP_CHAR_CHANGE_EVT 0x0002
    #define SBP_PERIODIC_EVT 0x0004
    #define SBP_CONN_EVT_END_EVT 0x0008

    /*********************************************************************
    * TYPEDEFS
    */

    // App event passed from profiles.
    typedef struct
    {
    appEvtHdr_t hdr; // event header.
    } sbpEvt_t;

    /*********************************************************************
    * GLOBAL VARIABLES
    */

    // Display Interface
    Display_Handle dispHandle = NULL;

    /*********************************************************************
    * LOCAL VARIABLES
    */

    // Entity ID globally used to check for source and/or destination of messages
    static ICall_EntityID selfEntity;

    // Semaphore globally used to post events to the application thread
    static ICall_Semaphore sem;

    // Clock instances for internal periodic events.
    static Clock_Struct periodicClock;

    // Queue object used for app messages
    static Queue_Struct appMsg;
    static Queue_Handle appMsgQueue;

    #if defined(FEATURE_OAD)
    // Event data from OAD profile.
    static Queue_Struct oadQ;
    static Queue_Handle hOadQ;
    #endif //FEATURE_OAD

    // events flag for internal application events.
    static uint16_t events;

    // Task configuration
    Task_Struct sbpTask;
    Char sbpTaskStack[SBP_TASK_STACK_SIZE];

    // Profile state and parameters
    //static gaprole_States_t gapProfileState = GAPROLE_INIT;

    // GAP - SCAN RSP data (max size = 31 bytes)
    static uint8_t scanRspData[] =
    {
    // complete name
    0x14, // length of this data
    GAP_ADTYPE_LOCAL_NAME_COMPLETE,
    'S',
    'i',
    'm',
    'p',
    'l',
    'e',
    'B',
    'L',
    'E',
    'P',
    'e',
    'r',
    'i',
    'p',
    'h',
    'e',
    'r',
    'a',
    'l',

    // connection interval range
    0x05, // length of this data
    GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
    LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
    HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
    LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
    HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),

    // Tx power level
    0x02, // length of this data
    GAP_ADTYPE_POWER_LEVEL,
    0 // 0dBm
    };

    // GAP - Advertisement data (max size = 31 bytes, though this is
    // best kept short to conserve power while advertisting)
    static uint8_t advertData[] =
    {
    // Flags; this sets the device to use limited discoverable
    // mode (advertises for 30 seconds at a time) instead of general
    // discoverable mode (advertises indefinitely)
    0x02, // length of this data
    GAP_ADTYPE_FLAGS,
    DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

    // service UUID, to notify central devices what services are included
    // in this peripheral
    #if !defined(FEATURE_OAD) || defined(FEATURE_OAD_ONCHIP)
    0x03, // length of this data
    #else //OAD for external flash
    0x05, // lenght of this data
    #endif //FEATURE_OAD
    GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all
    #ifdef FEATURE_OAD
    LO_UINT16(OAD_SERVICE_UUID),
    HI_UINT16(OAD_SERVICE_UUID),
    #endif //FEATURE_OAD
    #ifndef FEATURE_OAD_ONCHIP
    LO_UINT16(SIMPLEPROFILE_SERV_UUID),
    HI_UINT16(SIMPLEPROFILE_SERV_UUID)
    #endif //FEATURE_OAD_ONCHIP
    };

    // GAP GATT Attributes
    static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple BLE Peripheral";

    // Globals used for ATT Response retransmission
    static gattMsgEvent_t *pAttRsp = NULL;
    static uint8_t rspTxRetry = 0;

    /*********************************************************************
    * LOCAL FUNCTIONS
    */

    static void SimpleBLEPeripheral_init( void );
    static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1);

    static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg);
    static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg);
    static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg);
    static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState);
    static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID);
    static void SimpleBLEPeripheral_performPeriodicTask(void);
    static void SimpleBLEPeripheral_clockHandler(UArg arg);

    static void SimpleBLEPeripheral_sendAttRsp(void);
    static void SimpleBLEPeripheral_freeAttRsp(uint8_t status);

    static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState);
    #ifndef FEATURE_OAD_ONCHIP
    static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID);
    #endif //!FEATURE_OAD_ONCHIP
    static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state);

    #ifdef FEATURE_OAD
    void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
    uint8_t *pData);
    #endif //FEATURE_OAD


    /*********************************************************************
    * PROFILE CALLBACKS
    */

    // GAP Role Callbacks
    static gapRolesCBs_t SimpleBLEPeripheral_gapRoleCBs =
    {
    SimpleBLEPeripheral_stateChangeCB // Profile State Change Callbacks
    };

    // GAP Bond Manager Callbacks
    static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs =
    {
    NULL, // Passcode callback (not used by application)
    NULL // Pairing / Bonding state Callback (not used by application)
    };

    // Simple GATT Profile Callbacks
    #ifndef FEATURE_OAD_ONCHIP
    static simpleProfileCBs_t SimpleBLEPeripheral_simpleProfileCBs =
    {
    SimpleBLEPeripheral_charValueChangeCB // Characteristic value change callback
    };
    #endif //!FEATURE_OAD_ONCHIP

    #ifdef FEATURE_OAD
    static oadTargetCBs_t simpleBLEPeripheral_oadCBs =
    {
    SimpleBLEPeripheral_processOadWriteCB // Write Callback.
    };
    #endif //FEATURE_OAD

    /*********************************************************************
    * PUBLIC FUNCTIONS
    */

    /*********************************************************************
    * @fn SimpleBLEPeripheral_createTask
    *
    * @brief Task creation function for the Simple BLE Peripheral.
    *
    * @param None.
    *
    * @return None.
    */
    void SimpleBLEPeripheral_createTask(void)
    {
    Task_Params taskParams;

    // Configure task
    Task_Params_init(&taskParams);
    taskParams.stack = sbpTaskStack;
    taskParams.stackSize = SBP_TASK_STACK_SIZE;
    taskParams.priority = SBP_TASK_PRIORITY;

    Task_construct(&sbpTask, SimpleBLEPeripheral_taskFxn, &taskParams, NULL);
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_init
    *
    * @brief Called during initialization and contains application
    * specific initialization (ie. hardware initialization/setup,
    * table initialization, power up notification, etc), and
    * profile initialization/setup.
    *
    * @param None.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_init(void)
    {
    // ******************************************************************
    // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
    // ******************************************************************
    // Register the current thread as an ICall dispatcher application
    // so that the application can send and receive messages.
    ICall_registerApp(&selfEntity, &sem);

    #ifdef USE_RCOSC
    RCOSC_enableCalibration();
    #endif // USE_RCOSC

    #if defined( USE_FPGA )
    // configure RF Core SMI Data Link
    IOCPortConfigureSet(IOID_12, IOC_PORT_RFC_GPO0, IOC_STD_OUTPUT);
    IOCPortConfigureSet(IOID_11, IOC_PORT_RFC_GPI0, IOC_STD_INPUT);

    // configure RF Core SMI Command Link
    IOCPortConfigureSet(IOID_10, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_OUT, IOC_STD_OUTPUT);
    IOCPortConfigureSet(IOID_9, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_IN, IOC_STD_INPUT);

    // configure RF Core tracer IO
    IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT);
    #else // !USE_FPGA
    #if defined( DEBUG_SW_TRACE )
    // configure RF Core tracer IO
    IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
    #endif // DEBUG_SW_TRACE
    #endif // USE_FPGA

    // Create an RTOS queue for message from profile to be sent to app.
    appMsgQueue = Util_constructQueue(&appMsg);

    // Create one-shot clocks for internal periodic events.
    Util_constructClock(&periodicClock, SimpleBLEPeripheral_clockHandler,
    SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT);

    dispHandle = Display_open(Display_Type_LCD, NULL);

    // Setup the GAP
    GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL);

    // Setup the GAP Peripheral Role Profile
    {
    // For all hardware platforms, device starts advertising upon initialization
    uint8_t initialAdvertEnable = TRUE;

    // By setting this to zero, the device will go into the waiting state after
    // being discoverable for 30.72 second, and will not being advertising again
    // until the enabler is set back to TRUE
    uint16_t advertOffTime = 0;

    uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST;
    uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
    uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
    uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY;
    uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT;

    // Set the GAP Role Parameters
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
    &initialAdvertEnable);
    GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t),
    &advertOffTime);

    GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData),
    scanRspData);
    GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);

    GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t),
    &enableUpdateRequest);
    GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t),
    &desiredMinInterval);
    GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t),
    &desiredMaxInterval);
    GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t),
    &desiredSlaveLatency);
    GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t),
    &desiredConnTimeout);
    }

    // Set the GAP Characteristics
    GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);

    // Set advertising interval
    {
    uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;

    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt);
    }

    // Setup the GAP Bond Manager
    {
    uint32_t passkey = 0; // passkey "000000"
    uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8_t mitm = TRUE;
    uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    uint8_t bonding = TRUE;

    GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
    &passkey);
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
    GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
    GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
    }

    // Initialize GATT attributes
    GGS_AddService(GATT_ALL_SERVICES); // GAP
    GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
    DevInfo_AddService(); // Device Information Service

    #ifndef FEATURE_OAD_ONCHIP
    SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
    #endif //!FEATURE_OAD_ONCHIP

    #ifdef FEATURE_OAD
    VOID OAD_addService(); // OAD Profile
    OAD_register((oadTargetCBs_t *)&simpleBLEPeripheral_oadCBs);
    hOadQ = Util_constructQueue(&oadQ);
    #endif //FEATURE_OAD

    #ifdef IMAGE_INVALIDATE
    Reset_addService();
    #endif //IMAGE_INVALIDATE


    #ifndef FEATURE_OAD_ONCHIP
    // Setup the SimpleProfile Characteristic Values
    {
    uint8_t charValue1 = 1;
    uint8_t charValue2 = 2;
    uint8_t charValue3 = 3;
    uint8_t charValue4 = 4;
    uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };

    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),
    &charValue1);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),
    &charValue2);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),
    &charValue3);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
    &charValue4);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,
    charValue5);
    }

    // Register callback with SimpleGATTprofile
    SimpleProfile_RegisterAppCBs(&SimpleBLEPeripheral_simpleProfileCBs);
    #endif //!FEATURE_OAD_ONCHIP

    // Start the Device
    VOID GAPRole_StartDevice(&SimpleBLEPeripheral_gapRoleCBs);

    // Start Bond Manager
    VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);

    // Register with GAP for HCI/Host messages
    GAP_RegisterForMsgs(selfEntity);

    // Register for GATT local events and ATT Responses pending for transmission
    GATT_RegisterForMsgs(selfEntity);

    HCI_LE_ReadMaxDataLenCmd();

    #if defined FEATURE_OAD
    #if defined (HAL_IMAGE_A)
    Display_print0(dispHandle, 0, 0, "BLE Peripheral A");
    #else
    Display_print0(dispHandle, 0, 0, "BLE Peripheral B");
    #endif // HAL_IMAGE_A
    #else
    Display_print0(dispHandle, 0, 0, "BLE Peripheral");
    #endif // FEATURE_OAD
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_taskFxn
    *
    * @brief Application task entry point for the Simple BLE Peripheral.
    *
    * @param a0, a1 - not used.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
    {
    // Initialize application
    SimpleBLEPeripheral_init();

    // Application main loop
    for (;;)
    {
    // Waits for a signal to the semaphore associated with the calling thread.
    // Note that the semaphore associated with a thread is signaled when a
    // message is queued to the message receive queue of the thread or when
    // ICall_signal() function is called onto the semaphore.
    ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);

    if (errno == ICALL_ERRNO_SUCCESS)
    {
    ICall_EntityID dest;
    ICall_ServiceEnum src;
    ICall_HciExtEvt *pMsg = NULL;

    if (ICall_fetchServiceMsg(&src, &dest,
    (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
    {
    uint8 safeToDealloc = TRUE;

    if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
    {
    ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;

    // Check for BLE stack events first
    if (pEvt->signature == 0xffff)
    {
    if (pEvt->event_flag & SBP_CONN_EVT_END_EVT)
    {
    // Try to retransmit pending ATT Response (if any)
    SimpleBLEPeripheral_sendAttRsp();
    }
    }
    else
    {
    // Process inter-task message
    safeToDealloc = SimpleBLEPeripheral_processStackMsg((ICall_Hdr *)pMsg);
    }
    }

    if (pMsg && safeToDealloc)
    {
    ICall_freeMsg(pMsg);
    }
    }

    // If RTOS queue is not empty, process app message.
    while (!Queue_empty(appMsgQueue))
    {
    sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
    if (pMsg)
    {
    // Process message.
    SimpleBLEPeripheral_processAppMsg(pMsg);

    // Free the space from the message.
    ICall_free(pMsg);
    }
    }
    }

    if (events & SBP_PERIODIC_EVT)
    {
    events &= ~SBP_PERIODIC_EVT;

    Util_startClock(&periodicClock);

    // Perform periodic application task
    SimpleBLEPeripheral_performPeriodicTask();
    }

    #ifdef FEATURE_OAD
    while (!Queue_empty(hOadQ))
    {
    oadTargetWrite_t *oadWriteEvt = Queue_get(hOadQ);

    // Identify new image.
    if (oadWriteEvt->event == OAD_WRITE_IDENTIFY_REQ)
    {
    OAD_imgIdentifyWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
    }
    // Write a next block request.
    else if (oadWriteEvt->event == OAD_WRITE_BLOCK_REQ)
    {
    OAD_imgBlockWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
    }

    // Free buffer.
    ICall_free(oadWriteEvt);
    }
    #endif //FEATURE_OAD
    }
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_processStackMsg
    *
    * @brief Process an incoming stack message.
    *
    * @param pMsg - message to process
    *
    * @return TRUE if safe to deallocate incoming message, FALSE otherwise.
    */
    static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg)
    {
    uint8_t safeToDealloc = TRUE;

    switch (pMsg->event)
    {
    case GATT_MSG_EVENT:
    // Process GATT message
    safeToDealloc = SimpleBLEPeripheral_processGATTMsg((gattMsgEvent_t *)pMsg);
    break;

    case HCI_GAP_EVENT_EVENT:
    {
    // Process HCI message
    switch(pMsg->status)
    {
    case HCI_COMMAND_COMPLETE_EVENT_CODE:
    // Process HCI Command Complete Event
    break;

    default:
    break;
    }
    }
    break;

    default:
    // do nothing
    break;
    }

    return (safeToDealloc);
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_processGATTMsg
    *
    * @brief Process GATT messages and events.
    *
    * @return TRUE if safe to deallocate incoming message, FALSE otherwise.
    */
    static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg)
    {
    // See if GATT server was unable to transmit an ATT response
    if (pMsg->hdr.status == blePending)
    {
    // No HCI buffer was available. Let's try to retransmit the response
    // on the next connection event.
    if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
    SBP_CONN_EVT_END_EVT) == SUCCESS)
    {
    // First free any pending response
    SimpleBLEPeripheral_freeAttRsp(FAILURE);

    // Hold on to the response message for retransmission
    pAttRsp = pMsg;

    // Don't free the response message yet
    return (FALSE);
    }
    }
    else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
    {
    // ATT request-response or indication-confirmation flow control is
    // violated. All subsequent ATT requests or indications will be dropped.
    // The app is informed in case it wants to drop the connection.

    // Display the opcode of the message that caused the violation.
    Display_print1(dispHandle, 5, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
    }
    else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
    {
    // MTU size updated
    Display_print1(dispHandle, 5, 0, "MTU Size: $d", pMsg->msg.mtuEvt.MTU);
    }

    // Free message payload. Needed only for ATT Protocol messages
    GATT_bm_free(&pMsg->msg, pMsg->method);

    // It's safe to free the incoming message
    return (TRUE);
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_sendAttRsp
    *
    * @brief Send a pending ATT response message.
    *
    * @param none
    *
    * @return none
    */
    static void SimpleBLEPeripheral_sendAttRsp(void)
    {
    // See if there's a pending ATT Response to be transmitted
    if (pAttRsp != NULL)
    {
    uint8_t status;

    // Increment retransmission count
    rspTxRetry++;

    // Try to retransmit ATT response till either we're successful or
    // the ATT Client times out (after 30s) and drops the connection.
    status = GATT_SendRsp(pAttRsp->connHandle, pAttRsp->method, &(pAttRsp->msg));
    if ((status != blePending) && (status != MSG_BUFFER_NOT_AVAIL))
    {
    // Disable connection event end notice
    HCI_EXT_ConnEventNoticeCmd(pAttRsp->connHandle, selfEntity, 0);

    // We're done with the response message
    SimpleBLEPeripheral_freeAttRsp(status);
    }
    else
    {
    // Continue retrying
    Display_print1(dispHandle, 5, 0, "Rsp send retry: %d", rspTxRetry);
    }
    }
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_freeAttRsp
    *
    * @brief Free ATT response message.
    *
    * @param status - response transmit status
    *
    * @return none
    */
    static void SimpleBLEPeripheral_freeAttRsp(uint8_t status)
    {
    // See if there's a pending ATT response message
    if (pAttRsp != NULL)
    {
    // See if the response was sent out successfully
    if (status == SUCCESS)
    {
    Display_print1(dispHandle, 5, 0, "Rsp sent retry: %d", rspTxRetry);
    }
    else
    {
    // Free response payload
    GATT_bm_free(&pAttRsp->msg, pAttRsp->method);

    Display_print1(dispHandle, 5, 0, "Rsp retry failed: %d", rspTxRetry);
    }

    // Free response message
    ICall_freeMsg(pAttRsp);

    // Reset our globals
    pAttRsp = NULL;
    rspTxRetry = 0;
    }
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_processAppMsg
    *
    * @brief Process an incoming callback from a profile.
    *
    * @param pMsg - message to process
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg)
    {
    switch (pMsg->hdr.event)
    {
    case SBP_STATE_CHANGE_EVT:
    SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)pMsg->
    hdr.state);
    break;

    case SBP_CHAR_CHANGE_EVT:
    SimpleBLEPeripheral_processCharValueChangeEvt(pMsg->hdr.state);
    break;

    default:
    // Do nothing.
    break;
    }
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_stateChangeCB
    *
    * @brief Callback from GAP Role indicating a role state change.
    *
    * @param newState - new state
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState)
    {
    SimpleBLEPeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState);
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_processStateChangeEvt
    *
    * @brief Process a pending GAP Role state change event.
    *
    * @param newState - new state
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState)
    {
    #ifdef PLUS_BROADCASTER
    static bool firstConnFlag = false;
    #endif // PLUS_BROADCASTER

    switch ( newState )
    {
    case GAPROLE_STARTED:
    {
    uint8_t ownAddress[B_ADDR_LEN];
    uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];

    GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);

    // use 6 bytes of device address for 8 bytes of system ID value
    systemId[0] = ownAddress[0];
    systemId[1] = ownAddress[1];
    systemId[2] = ownAddress[2];

    // set middle bytes to zero
    systemId[4] = 0x00;
    systemId[3] = 0x00;

    // shift three bytes up
    systemId[7] = ownAddress[5];
    systemId[6] = ownAddress[4];
    systemId[5] = ownAddress[3];

    DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);

    // Display device address
    Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(ownAddress));
    Display_print0(dispHandle, 2, 0, "Initialized");
    }
    break;

    case GAPROLE_ADVERTISING:
    Display_print0(dispHandle, 2, 0, "Advertising");
    break;

    #ifdef PLUS_BROADCASTER
    /* After a connection is dropped a device in PLUS_BROADCASTER will continue
    * sending non-connectable advertisements and shall sending this change of
    * state to the application. These are then disabled here so that sending
    * connectable advertisements can resume.
    */
    case GAPROLE_ADVERTISING_NONCONN:
    {
    uint8_t advertEnabled = FALSE;

    // Disable non-connectable advertising.
    GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
    &advertEnabled);

    advertEnabled = TRUE;

    // Enabled connectable advertising.
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
    &advertEnabled);

    // Reset flag for next connection.
    firstConnFlag = false;

    SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
    }
    break;
    #endif //PLUS_BROADCASTER

    case GAPROLE_CONNECTED:
    {
    linkDBInfo_t linkInfo;
    uint8_t numActive = 0;

    Util_startClock(&periodicClock);

    numActive = linkDB_NumActive();

    // Use numActive to determine the connection handle of the last
    // connection
    if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS )
    {
    Display_print1(dispHandle, 2, 0, "Num Conns: %d", (uint16_t)numActive);
    Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(linkInfo.addr));
    }
    else
    {
    uint8_t peerAddress[B_ADDR_LEN];

    GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);

    Display_print0(dispHandle, 2, 0, "Connected");
    Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddress));
    }

    #ifdef PLUS_BROADCASTER
    // Only turn advertising on for this state when we first connect
    // otherwise, when we go from connected_advertising back to this state
    // we will be turning advertising back on.
    if (firstConnFlag == false)
    {
    uint8_t advertEnabled = FALSE; // Turn on Advertising

    // Disable connectable advertising.
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
    &advertEnabled);

    // Set to true for non-connectabel advertising.
    advertEnabled = TRUE;

    // Enable non-connectable advertising.
    GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
    &advertEnabled);
    firstConnFlag = true;
    }
    #endif // PLUS_BROADCASTER
    }
    break;

    case GAPROLE_CONNECTED_ADV:
    Display_print0(dispHandle, 2, 0, "Connected Advertising");
    break;

    case GAPROLE_WAITING:
    Util_stopClock(&periodicClock);
    SimpleBLEPeripheral_freeAttRsp(bleNotConnected);

    Display_print0(dispHandle, 2, 0, "Disconnected");

    // Clear remaining lines
    Display_clearLines(dispHandle, 3, 5);
    break;

    case GAPROLE_WAITING_AFTER_TIMEOUT:
    SimpleBLEPeripheral_freeAttRsp(bleNotConnected);

    Display_print0(dispHandle, 2, 0, "Timed Out");

    // Clear remaining lines
    Display_clearLines(dispHandle, 3, 5);

    #ifdef PLUS_BROADCASTER
    // Reset flag for next connection.
    firstConnFlag = false;
    #endif //#ifdef (PLUS_BROADCASTER)
    break;

    case GAPROLE_ERROR:
    Display_print0(dispHandle, 2, 0, "Error");
    break;

    default:
    Display_clearLine(dispHandle, 2);
    break;
    }

    // Update the state
    //gapProfileState = newState;
    }

    #ifndef FEATURE_OAD_ONCHIP
    /*********************************************************************
    * @fn SimpleBLEPeripheral_charValueChangeCB
    *
    * @brief Callback from Simple Profile indicating a characteristic
    * value change.
    *
    * @param paramID - parameter ID of the value that was changed.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID)
    {
    SimpleBLEPeripheral_enqueueMsg(SBP_CHAR_CHANGE_EVT, paramID);
    }
    #endif //!FEATURE_OAD_ONCHIP

    /*********************************************************************
    * @fn SimpleBLEPeripheral_processCharValueChangeEvt
    *
    * @brief Process a pending Simple Profile characteristic value change
    * event.
    *
    * @param paramID - parameter ID of the value that was changed.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID)
    {
    #ifndef FEATURE_OAD_ONCHIP
    uint8_t newValue;

    switch(paramID)
    {
    case SIMPLEPROFILE_CHAR1:
    SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);

    Display_print1(dispHandle, 4, 0, "Char 1: %d", (uint16_t)newValue);
    break;

    case SIMPLEPROFILE_CHAR3:
    SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);

    Display_print1(dispHandle, 4, 0, "Char 3: %d", (uint16_t)newValue);
    break;

    default:
    // should not reach here!
    break;
    }
    #endif //!FEATURE_OAD_ONCHIP
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_performPeriodicTask
    *
    * @brief Perform a periodic application task. This function gets called
    * every five seconds (SBP_PERIODIC_EVT_PERIOD). In this example,
    * the value of the third characteristic in the SimpleGATTProfile
    * service is retrieved from the profile, and then copied into the
    * value of the the fourth characteristic.
    *
    * @param None.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_performPeriodicTask(void)
    {
    #ifndef FEATURE_OAD_ONCHIP
    uint8_t valueToCopy;

    // Call to retrieve the value of the third characteristic in the profile
    if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS)
    {
    // Call to set that value of the fourth characteristic in the profile.
    // Note that if notifications of the fourth characteristic have been
    // enabled by a GATT client device, then a notification will be sent
    // every time this function is called.
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
    &valueToCopy);
    }
    #endif //!FEATURE_OAD_ONCHIP
    }


    #ifdef FEATURE_OAD
    /*********************************************************************
    * @fn SimpleBLEPeripheral_processOadWriteCB
    *
    * @brief Process a write request to the OAD profile.
    *
    * @param event - event type:
    * OAD_WRITE_IDENTIFY_REQ
    * OAD_WRITE_BLOCK_REQ
    * @param connHandle - the connection Handle this request is from.
    * @param pData - pointer to data for processing and/or storing.
    *
    * @return None.
    */
    void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
    uint8_t *pData)
    {
    oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t) + \
    sizeof(uint8_t) * OAD_PACKET_SIZE);

    if ( oadWriteEvt != NULL )
    {
    oadWriteEvt->event = event;
    oadWriteEvt->connHandle = connHandle;

    oadWriteEvt->pData = (uint8_t *)(&oadWriteEvt->pData + 1);
    memcpy(oadWriteEvt->pData, pData, OAD_PACKET_SIZE);

    Queue_put(hOadQ, (Queue_Elem *)oadWriteEvt);

    // Post the application's semaphore.
    Semaphore_post(sem);
    }
    else
    {
    // Fail silently.
    }
    }
    #endif //FEATURE_OAD

    /*********************************************************************
    * @fn SimpleBLEPeripheral_clockHandler
    *
    * @brief Handler function for clock timeouts.
    *
    * @param arg - event type
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_clockHandler(UArg arg)
    {
    // Store the event.
    events |= arg;

    // Wake up the application.
    Semaphore_post(sem);
    }

    /*********************************************************************
    * @fn SimpleBLEPeripheral_enqueueMsg
    *
    * @brief Creates a message and puts the message in RTOS queue.
    *
    * @param event - message event.
    * @param state - message state.
    *
    * @return None.
    */
    static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state)
    {
    sbpEvt_t *pMsg;

    // Create dynamic pointer to message.
    if ((pMsg = ICall_malloc(sizeof(sbpEvt_t))))
    {
    pMsg->hdr.event = event;
    pMsg->hdr.state = state;

    // Enqueue the message.
    Util_enqueueMsg(appMsgQueue, sem, (uint8*)pMsg);
    }
    }

    /*********************************************************************
    *********************************************************************/
    ****************************************************************************************

    Thanks,
    Mike
  • Hi Vy Luu,

    I guess you didn't find anything in the large dump source code dump I sent in my last message. I have worked on things with this project other than SPI while waiting for someone to answer but will be getting back to SPI soon. I also emailed support@ti.com and haven't heard back yet.

    I do not have a logic analyzer, but I do have a two-channel scope. This board is small and difficult to probe, but I can say that the SPI write/readback call does make the SPI peripheral generate clock and data signals, so I know the library call is functioning, but it never returns.

    Thank you for your feedback.

    Mike
  • HI Michael McCully,
    Oh Sorry! I missed your last message. I dont find anything about your code. However, I dont see any code about how you call SPI tranfer in your code. Please send me this code that initilize and use SPI_transfer

  • Hello Vy Luu,

    Below is the code with a call to SPI_Transfer() using blocking mode. It never returns. It locks up waiting for a semaphore, as I showed in an earlier post.

    In the code I sent last, I included board.c/.h and I think also simple_peripheral.c. Did you have a chance to look at those?

    void ADS1293_init() {
    SPI_Params_init(&params);
    params.transferMode = SPI_MODE_BLOCKING;
    params.bitRate = 1000000;
    params.frameFormat = SPI_POL1_PHA0;
    params.dataSize = 16;
    params.mode = SPI_MASTER;

    transaction.count = 1;
    transaction.txBuf = txBuf;
    transaction.rxBuf = rxBuf;

    handle = SPI_open(0,&params);
    if (handle != NULL) {
    SPI_transfer(handle,&transaction);
    }
    }

    Thanks,
    Mike McCully