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.

CC2640R2F: SDKv5.30: Changing advertisement data from another task causes hang?

Part Number: CC2640R2F

Hi, 

I have 2 task

/* Kick off Application Tasks - Priority 1 */
MidgetSensor_createTask();
NTM88_createTask();

The NTM88 task collects sensor data every 2 seconds, then copies the sensor data to advertData[]. If I do this below it hangs. However, if I update the advertisement data at MidgetSensor task it works. I create a periodic clock that will update the advertisement data every 2 seconds.

advertData.ntm88data[0] = gSendData.array_data[0];
  advertData.ntm88data[1] = gSendData.array_data[1];
  advertData.ntm88data[2] = gSendData.array_data[2];
  advertData.ntm88data[3] = gSendData.array_data[3];
  advertData.ntm88data[4] = gSendData.array_data[4];
  advertData.ntm88data[5] = gSendData.array_data[5];
  advertData.ntm88data[6] = gSendData.array_data[6];
  advertData.ntm88data[7] = gSendData.array_data[7];
  advertData.ntm88data[8] = gSendData.array_data[8];
  advertData.ntm88data[9] = gSendData.array_data[9];
  advertData.ntm88data[10] = gSendData.array_data[10];
  advertData.ntm88data[11] = gSendData.array_data[11];
  advertData.ntm88data[12] = gSendData.array_data[12];
  advertData.ntm88data[13] = gSendData.array_data[13];

  initialAdvertEnable = FALSE;


  GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED,
                       sizeof(uint8_t),
                       &initialAdvertEnable);

  GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(NTM88AdvData_t), (void *)&advertData);

  initialAdvertEnable = TRUE;

  GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED,
                       sizeof(uint8_t),
                       &initialAdvertEnable);

-kel

  • Hi Ammar,

    It did not work it still hangs. From the guide there is no OSAL_MAX_NUM_PROXY_TASKS predefined symbol at stack project. The advertisement data gets updated if I do it at MidgetSensor task using a periodic 2 seconds timer. But, that way does not look okay. I will share my entire ntm88_app.c for your review. This project is CC2640R2F + NXP NTM88 TPMS. The base example program I used for this project is Simple Peripheral Off Chip OAD from SDKv5.30.

    #include <string.h>
    
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/knl/Queue.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/display/Display.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/SPI.h>
    
    #include <icall.h>
    #include "util.h"
    #include "att_rsp.h"
    
    /* This Header file contains all BLE API and icall structure definition */
    #include "icall_ble_api.h"
    
    #include "peripheral.h"
    
    /* Example/Board Header files */
    #include "Board.h"
    
    #include "ntm88_app.h"
    #include "midget_sensor_oad_offchip.h"
    
    
    /*********************************************************************
     * CONSTANTS
     */
    
    // Task configuration
    #define NTM88_TASK_PRIORITY                     1
    
    #ifndef NTM88_TASK_STACK_SIZE
    #define NTM88_TASK_STACK_SIZE                   644
    #endif
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    
    // Entity ID globally used to check for source and/or destination of messages
    static ICall_EntityID selfEntity2;
    
    // Event globally used to post local events and pend on system and
    // local events.
    static ICall_SyncHandle syncEvent2;
    
    // Task configuration
    Task_Struct ntm88Task;
    Char ntm88TaskStack[NTM88_TASK_STACK_SIZE];
    
    Semaphore_Handle rptSem;
    Semaphore_Params sP;
    
    static uint8_t gau8TxData[NB_16BIT_XFERS * 2] = {0};
    static uint8_t gau8RxData[NB_16BIT_XFERS * 2] = {0};
    
    SPI_Handle      masterSpi = NULL;
    SPI_Params      spiParams;
    SPI_Transaction transaction;
    
    typedef struct Send_Data
    {
        uint8_t nb_bytes;
        uint8_t array_data[14];
    } t_Send_Data;
    
    t_Send_Data gSendData = {0, {0}};
    
    /* Semaphore to block master until slave is ready for transfer */
    //sem_t masterSem;
    
    /* Pin driver handles */
    static PIN_Handle NTM88PinHandle;
    static PIN_Handle BoardPinHandle;
    
    /* Global memory storage for a PIN_Config table */
    static PIN_State NTM88PinState;
    static PIN_State BoardPinState;
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config NTM88PinTable[] = {
    
        Board_NTM88_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PULLUP | PIN_DRVSTR_MAX,   /* Configure MOSI first as output for NTM88 KBI input */
        PIN_TERMINATE
    };
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config BoardPinTable[] = {
        Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,     /* LED initially on */
        Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,      /* LED initially off */
        Board_WAKE_UP | PIN_INPUT_EN | PIN_NOPULL | PIN_IRQ_POSEDGE | PIN_HYSTERESIS,          /* Wake Up pin driven by NTM88 */
        PIN_TERMINATE
    };
    
    /*********************************************************************
     * PROFILE CALLBACKS
     */
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    
    //Local Function declaration
    static uint8_t u8SpiFillTxBuffer(void);
    static bool bSpiGetParity(uint8_t u8parityByte);
    static void vfnSpiFillBufferRead(uint16_t u16address, uint8_t *i);
    static void vfnSpiFillBufferWrite(uint16_t u16data, uint8_t *i);
    static void vfnSpiFillBufferCmd(uint16_t u16data, uint8_t *i);
    static uint8_t u8SpiGetStatus(uint16_t u16SpiRsp);
    static uint8_t u8SpiGetData(uint16_t u16SpiRsp);
    static uint8_t u8SpiStoreData(void);
    static void SPI_Init(void);
    
    static void NTM88_taskFxn(UArg a0, UArg a1);
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    
    /*********************************************************************
     * @fn      u8SpiFillTxBuffer
     *
     * @brief   Fills the SPI transmission buffer with commands to read the sensor
     *          data and then let the NTM88 CPU resume.
     *
     * @param   None.
     *
     * @return  None.
     */
    static uint8_t u8SpiFillTxBuffer(void)
    {
      uint8_t i, buffer_index;
      uint16_t u16address;
    
      // We fill the buffer from the beginning
      buffer_index = 0;
    
      /***** READ commands to get the sensor data ******************/
      u16address = ADDR_FIRST_DATA_BYTE;
      for (i = 0; i < NB_DATA_BYTES; i++)
      {
        vfnSpiFillBufferRead(u16address++, &buffer_index);
      }
    
      /***** WRITE commands to let the NTM88 resume operations *****/
      vfnSpiFillBufferWrite(ADDR_SPIOPS, &buffer_index);
      vfnSpiFillBufferWrite(0x00, &buffer_index);
    
      // Note that it would be necessary to perform an additional transfer to read the WRITE command status
      return buffer_index;
    }
    
    /*********************************************************************
     * @fn      bSpiGetParity
     *
     * @brief   Calculates and returns the parity of the byte passed as parameter
     *
     * @param   u8parityByte, the byte of which we want to know the parity
     *
     * @return  parity
     */
    static bool bSpiGetParity(uint8_t u8parityByte)
    {
      uint8_t i = 0;
      uint8_t u8count = 0;
    
      for(i = 0; i < 7 ; i++)
      {
        if (u8parityByte%2 == 1) u8count++; //increments count
        u8parityByte /= 2;
      }
      return (u8count%2 != 0);
    }
    
    /*********************************************************************
     * @fn      vfnSpiFillBufferRead
     *
     * @brief   Adds a READ command to the SPI buffer and increments the buffer
     *          index
     *
     * @param   u16address, the address to read
     *               *i, the pointer to the index in the buffer at which the command
     *          should be written
     *
     * @return
     */
    static void vfnSpiFillBufferRead(uint16_t u16address, uint8_t *i)
    {
      vfnSpiFillBufferCmd(u16address, i);
    }
    
    /*********************************************************************
     * @fn      vfnSpiFillBufferWrite
     *
     * @brief   Adds a WRITE command to the SPI buffer and increments the buffer
     *          index
     *
     * @param   u16data, the data to write, which can be the address or the value
     *          to write
     *               *i, the pointer to the index in the buffer at which the command
     *          should be written
     *
     * @return
     */
    static void vfnSpiFillBufferWrite(uint16_t u16data, uint8_t *i)
    {
      u16data += (1<<13);
      vfnSpiFillBufferCmd(u16data, i);
    }
    
    /*********************************************************************
     * @fn      vfnSpiFillBufferCmd
     *
     * @brief   Formats the command, stores it in the SPI buffer and increments
     *          the buffer index
     *
     * @param   u16data, the data to write, which can be the address or the value
     *          to write
     *               *i, the pointer to the index in the buffer at which the command
     *          should be written
     *
     * @return
     */
    static void vfnSpiFillBufferCmd(uint16_t u16data, uint8_t *i)
    {
      /*
       * 16 bits format
       * OP Command for Write ---> 1 / for Read ---> 0
       * OP | A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 | P1 P0
       * x    Address    Address   Address  Address       Parity
       * P1 -> Parity for OP A12 A11 A10 A9 A8 A7
       * P2 -> Parity for A6  A5  A4  A3 A2 A1 A0
       */
    
      uint8_t u8parityByteMSB=0, u8parityByteLSB=0;
      bool bP0=0, bP1=0;
      uint8_t u8parityDuo=0;
      uint16_t u16CommandToTPMS=0;
    
      u8parityByteMSB = (uint8_t)(u16data / 128);
      u8parityByteLSB = (uint8_t)(u16data % 128);
    
      bP1 = bSpiGetParity(u8parityByteMSB);
      bP0 = bSpiGetParity(u8parityByteLSB);
    
      // Combining P1 and P0
      u8parityDuo = 2*bP1 + bP0;
    
      u16CommandToTPMS = (uint16_t)(u16data<<2) + u8parityDuo;
      gau8TxData[(*i)++] = u16CommandToTPMS & 0xFF; // LSByte first
      gau8TxData[(*i)++] = u16CommandToTPMS / 256; // MSByte second
    
      return;
    }
    
    /*********************************************************************
     * @fn      u8SpiGetStatus
     *
     * @brief   Extracts the 8-bit status from the 16-bit response
     *
     * @param   u16SpiRsp
     *
     * @return
     */
    static uint8_t u8SpiGetStatus(uint16_t u16SpiRsp)
    {
      return(u16SpiRsp>>10) & 0x1F;
    }
    
    /*********************************************************************
     * @fn      u8SpiGetData
     *
     * @brief   Extracts the 8-bit data from the 16-bit response
     *
     * @param   None.
     *
     * @return  None.
     */
    static uint8_t u8SpiGetData(uint16_t u16SpiRsp)
    {
      return(u16SpiRsp>>2) & 0xFF;
    }
    
    /*********************************************************************
     * @fn      u8SpiStoreData
     *
     * @brief   Stores the data read via SPI
     *
     * @param   None.
     *
     * @return  None.
     */
    static uint8_t u8SpiStoreData(void)
    {
      uint8_t i;
      uint8_t u8offset_read_data;
      uint16_t u16spi_response;
      uint8_t u8read_status = 0;
    
      /* We discard the response of the first 16-bit xfer since it contains no information,
         so we discard indexes 0 and 1 */
      u8offset_read_data = 2;
    
      for (i = 0; i < NB_DATA_BYTES; i++)
      {
        // First, re-assemble the 16-bit response
        u16spi_response = (uint16_t)(gau8RxData[2*i+1+u8offset_read_data]); // MSByte
        u16spi_response <<= 8;
        u16spi_response &= 0xFF00;
        u16spi_response |= gau8RxData[2*i+u8offset_read_data]; // LSByte
        // Then extract the data and status from it
        gSendData.array_data[i] = u8SpiGetData(u16spi_response);
        u8read_status |= u8SpiGetStatus(u16spi_response);
      }
    
      gSendData.nb_bytes = NB_DATA_BYTES;
    
      advertData.ntm88data[0] = gSendData.array_data[0];
      advertData.ntm88data[1] = gSendData.array_data[1];
      advertData.ntm88data[2] = gSendData.array_data[2];
      advertData.ntm88data[3] = gSendData.array_data[3];
      advertData.ntm88data[4] = gSendData.array_data[4];
      advertData.ntm88data[5] = gSendData.array_data[5];
      advertData.ntm88data[6] = gSendData.array_data[6];
      advertData.ntm88data[7] = gSendData.array_data[7];
      advertData.ntm88data[8] = gSendData.array_data[8];
      advertData.ntm88data[9] = gSendData.array_data[9];
      advertData.ntm88data[10] = gSendData.array_data[10];
      advertData.ntm88data[11] = gSendData.array_data[11];
      advertData.ntm88data[12] = gSendData.array_data[12];
      advertData.ntm88data[13] = gSendData.array_data[13];
    
      GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(NTM88AdvData_t), (void *)&advertData);
    
      return u8read_status;
    }
    
    /*********************************************************************
     * @fn      slaveReadyFxn
     *
     * @brief   Callback function for the GPIO interrupt on Board_SPI_SLAVE_READY
     *
     * @param   handle, pinId.
     *
     * @return  None.
     */
    void slaveReadyFxn(PIN_Handle handle, PIN_Id pinId)
    {
      if(PIN_getInputValue(Board_WAKE_UP) == 1)
      {
        Semaphore_post(rptSem);
      }
    }
    
    /*********************************************************************
     * @fn      SPI_Init
     *
     * @brief   Intialize the NTM88 SPI
     *
     * @param   None.
     *
     * @return  None.
     */
    static void SPI_Init(void)
    {
      SPI_init();
      /* Open SPI as master (default) */
      SPI_Params_init(&spiParams);
      spiParams.frameFormat = SPI_POL0_PHA0; /*!< SPI mode Polarity 0 Phase 0 */
      spiParams.bitRate = 100000;
      spiParams.dataSize = 16;
      masterSpi = SPI_open(Board_SPI_MASTER, &spiParams);
      if(masterSpi == NULL)
      {
        while(1);
      }
    }
    
    /*********************************************************************
     * @fn      NTM88App_createTask
     *
     * @brief   Task creation function for the NTM88 Task.
     *
     * @param   None.
     *
     * @return  None.
     */
    void NTM88_createTask(void)
    {
      Task_Params taskParams;
    
      Semaphore_Params_init(&sP);
      sP.mode = Semaphore_Mode_BINARY;
      rptSem = Semaphore_create(1, &sP, Error_IGNORE);
    
      // Configure task
      Task_Params_init(&taskParams);
      taskParams.arg0 = (UArg)rptSem;
      taskParams.stack = ntm88TaskStack;
      taskParams.stackSize = NTM88_TASK_STACK_SIZE;
      taskParams.priority = NTM88_TASK_PRIORITY;
    
      Task_construct(&ntm88Task, NTM88_taskFxn, &taskParams, NULL);
    }
    
    /*********************************************************************
     * @fn      NTM88_init
     *
     * @brief
     *
     * @param   None.
     *
     * @return  None.
     */
    void NTM88_init(void)
    {
    
      BoardPinHandle = PIN_open(&BoardPinState, BoardPinTable);
    
      if(!BoardPinHandle)
      {
       /* Error initializing board pins */
       while(1);
      }
    
      /* Setup callback for button pins */
      if (PIN_registerIntCb(BoardPinHandle, &slaveReadyFxn) != 0)
      {
        /* Error registering button callback function */
        while(1);
      }
    }
    
    /*********************************************************************
     * @fn      NTM88_WakeUp_Enable
     *
     * @brief   Enable the DIO21 Board Wake Up pin interrupt
     *
     * @param   None.
     *
     * @return  None.
     */
    void NTM88_WakeUp_Enable(void)
    {
      PIN_setConfig(NTM88PinHandle, PIN_BM_IRQ, Board_WAKE_UP | PIN_INPUT_EN | PIN_NOPULL | PIN_IRQ_POSEDGE | PIN_HYSTERESIS);
      Task_setPri(Task_handle(&ntm88Task), NTM88_TASK_PRIORITY);
    }
    
    /*********************************************************************
     * @fn      NTM88_WakeUp_Disable
     *
     * @brief   Disable the DIO21 Board Wake Up pin interrupt
     *
     * @param   None.
     *
     * @return  None.
     */
    void NTM88_WakeUp_Disable(void)
    {
      //SPI_close(masterSpi);
      PIN_setConfig(NTM88PinHandle, PIN_BM_IRQ, Board_WAKE_UP | PIN_IRQ_DIS);
      Task_setPri(Task_handle(&ntm88Task), -1);
    }
    
    /*********************************************************************
     * @fn      NTM88_taskFxn
     *
     * @brief   Application task entry point for the Simple Peripheral.
     *
     * @param   a0, a1 - not used.
     *
     * @return  None.
     */
    static void NTM88_taskFxn(UArg a0, UArg a1)
    {
      uint8_t u8xfer_nb_bytes = 0;
      bool transferOK = false;
    
      // ******************************************************************
      // NO 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(&selfEntity2, &syncEvent2);
    
      Semaphore_Handle rptSem = (Semaphore_Handle)a0;
    
      while(1)
      {
    
        NTM88PinHandle = PIN_open(&NTM88PinState, NTM88PinTable);
    
        if(!NTM88PinHandle)
        {
           /* Error initializing button pins */
           while(1);
        }
    
        PIN_setOutputValue(NTM88PinHandle, Board_NTM88_MOSI, 1);
    
        /*
         * Wait until slave is ready for transfer; slave will pull
         * Board_SPI_SLAVE_READY low to high.
         */
    
        Semaphore_pend(rptSem, BIOS_WAIT_FOREVER);
    
        PIN_setOutputValue(NTM88PinHandle, Board_NTM88_MOSI, 0); //Set NTM88 KBI pin low
    
        while (PIN_getInputValue(Board_WAKE_UP) == 1) {} //Wait for NTM88 to set Board_WAKE_UP to 0
    
        /* Toggle user LED, indicating a SPI transfer is in progress */
        PIN_setOutputValue(BoardPinHandle, Board_PIN_LED1, !PIN_getOutputValue(Board_PIN_LED1));
    
        PIN_close(NTM88PinHandle);
    
        u8xfer_nb_bytes = u8SpiFillTxBuffer();
    
        SPI_Init();
    
        /* Initialize master SPI transaction structure */
        transaction.count = u8xfer_nb_bytes;
        transaction.txBuf = (void *) gau8TxData;
        transaction.rxBuf = (void *) gau8RxData;
    
        /* Perform SPI transfer */
        transferOK = SPI_transfer(masterSpi, &transaction);
        if (transferOK) {
    
        }
        else {
    
        }
    
        u8SpiStoreData();
    
        SPI_close(masterSpi);
      } //while(1) end
    }
    

    -kel

     

  • Hey Kel,

    Apologies for the delay in looking into this.

    Looking at your code above, I see a few things that can cause the issue you describe.

    ICall_registerApp(&selfEntity2, &syncEvent2);

    It's OK to use a second syncEvent and selfEntity, however you need to add the Event_pend() line to synchronize the two Icall enabled tasks . Make sure to pass in syncEvent2 to the Event_pend call so you can wake up for the right event.

    More importantly,  I too see OSAL_MAX_NUM_PROXY_TASKS is not a preprocessor define. I suggest adding this. If not defined in the project settings, the  project will default to the value inside osal.c (which is 2). Since this define is not being incremented, Icall will abort.

    So in short, make sure to increment ICALL_MAX_NUM_ENTITIES and ICALL_MAX_NUM_TASKS in the application project, and increment OSAL_MAX_NUM_PROXY_TASKS (add a predefined symbol) as well in the stack project.

  • Thanks, it worked. I did not need the Event_pend(). It worked without the Event_pend().

    -kel