DA14531MOD - Examples for using a new task for

Hi,

I am currently working on DA14531MOD Development Kit-Pro board (DA14531MOD-00DEVKT-P) using the SDK - 6.0.16.1144  for a Project. In the project, I want to make a UART communication whenever the BLE device is written with some data packet(WRITE operation) from the Mobile App(in this case SmartBond). I have to switch the context from the write handler in order to implement the UART send and receive code.
But I am confused if for the implementation, do we need the creation of a new task, or could it be handled by any APIs(that is switching to a new context, where the UART communication code would be written) inbuilt in the SDK.
Please confirm what should be the way ahead. Also can you provide an example for the solution which you suggest?

Thank you in advance!

  • Hi Divakaran,

    Thank you for your interest in our BLE products and your question online.

    Firstly, I would recommend using our newest SDK v.6.0.18.1182.1.
    My understanding is that when you send a Write Operation from the Mobile App inside one of your characteristics that you want something to be printed in your terminal via UART. Have I misunderstood something? 
    I believe you have implemented your user_catch_rest_hndl function and inside it you have a case for your write operation, that probably looks something like this:

     case SVC1_IDX_CONTROL_POINT_VAL:
                        user_svc1_ctrl_wr_ind_handler(msgid, msg_param, dest_id, src_id);
                        break;

    Inside the user_svc1_ctrl_wr_ind_handler you can just call arch_printf (to format and transmit a string via the UART) or arch_puts (to transmit a simple string via the UART). These functions can print your messages or variables you want in your terminal. Do you want to be able to write from your terminal in order to initiate a different action on your device?
    Of course, you will have to add (if you want to use arch_printf or arch_puts):
    #include "arch_console.h"
    

    Also, you must go toda1458x_config_basic.h file and define CFG_PRINTF in order to activate UART Console Print. Inside user_periph_setup.h you can find the UART2 Pin configuration so you can use whatever pin suits you:
    #if defined (__DA14531__)
        #define UART2_TX_PORT           GPIO_PORT_0
        #define UART2_TX_PIN            GPIO_PIN_6
    #else
        #define UART2_TX_PORT           GPIO_PORT_0
        #define UART2_TX_PIN            GPIO_PIN_4
    #endif
    

    You should connect a cable from the middle pin of UTX on J1 header to the Pin you have selected on J2 header. 

    Kind Regards,
    OV_Renesas

  • Hi,

    Thank you for the quick reply. 

    So, in my case, I was trying to create a project to write a data from Mobile APP to the device which will transfer the data to the UART and the response to the APP has to be sent back from UART Rx (App Read). So, the data from BLE would have to be transmitted to the UART and need to wait till the UART Receive. 
    As of now how I was proceeding is, processing UART Send and Receive in the "gattc_write_req_ind_handler" in 'cust1_task.c'. But while waiting for the UART receive inside this handler, the App was showing "Operation Failed". But with no wait inside the handler, the BLE write operation was successful. My assumption was waiting inside that handler created the issue, so I thought of creating a new task and send this data to that task, where the UART Receive and UART Send can be processed. 
    I was trying to create a new task, but I could not proceed further with that, which is when I raised this query.
    Regarding the solution provided, as of now the definition of "app_process_catch_rest_cb" part is commented in the code and I am not using it.
    So, would you suggest me to look into the "user_catch_rest_hndl" function and if so, can you help me in configuring.
    Also, if you can share me some example codes, it will be really helpful.

    Again, Thanks in advance.

  • Hi Divakaran,

    The gattc_write_req_ind_handler is inside sdk\ble_stack\profiles\custom]custs\src\custs1_task.c. We highly recommend to not modify any files inside the SDK folders. You should use the user folders to build your application. 

    I would recommend checking our DA145xx Tutorial Create a Custom GATT Profile: DA145XX Tutorial Create a Custom GATT Profile — DA145XX Tutorial Create a Custom GATT Profile (renesas.com)
    You can also check our ble_app_peripheral, prox_reporter and ble_app_sleepmode examples. These examples use a custom GATT profile and implement different functionality for their characteristics.
    You should use user_catch_rest_hndl and implement your handler for write operations. Inside there you can send what you want to your PC via UART. 
    I would also suggest checking DA14531 Datasheet, 6.2.1 Interrupts, page:73

    You can implement an UART interrupt when you want to write something back from your PC so it can trigger the interrupt and call a specific function that will update your characteristics.

    Kind Regards,
    OV_Renesas

  • Hi,

    Thanks for the information. It was really helpful.

    So as per your input, I am proceeding with my implementation. I have few more doubts/observation, which I would like to clarify with you. I was referring to the 'ble_app_peripheral' example which you had mentioned. In that, I was modifying the 'user_svc1_long_val_wr_ind_handler'.

    While trying the above code, in SmartBond app, after writing a value from the app, the App was failing and returning a pop-up saying "Operation Failed". But on commenting the line "while (!uart_receive_finished);", the Write Operation (from App) was successful.

    Does that mean, I cannot wait inside this handler?

    The UART Receive part is referred from the UART example in '6.0.16.1144\projects\target_apps\peripheral_examples\uart\Keil_5'.

    Also I have to receive a variable length payload from UART using interrupt , but I am not able to find a possible method to do so. All I can think of is setting a length of 1 byte and on UART ISR(uart_receive_cb()), I would have to re-register UART Receive again. But registering a new UART Receive will disable IRQ and this might create a Race condition for me since UART is continuously streaming data.

    So can you suggest me the solutions for the above mentioned issues.

    Thanks again and waiting for a quick reply.

  • Hi Divakaran,

    Yes, you should not wait undefinedly inside a handler.
    I would recommend implementing an app_easy_timer to check every 1/2/3 seconds (or whatever time you want) if you have received from UART the data you want. After confirming that you have received the data you can continue by updating the characteristic you want. 
    You should not forget to cancel the timer when you had confirmed that you received the data.

    Kind Regards,
    OV_Renesas

  • Thanks again for the quick reply. Can you give me a solution for this part of the question as well:

    "Also I have to receive a variable length payload from UART using interrupt , but I am not able to find a possible method to do so. All I can think of is setting a length of 1 byte and on UART ISR(uart_receive_cb()), I would have to re-register UART Receive again. But registering a new UART Receive will disable IRQ and this might create a Race condition for me since UART is continuously streaming data."

    Thank you.

  • Hi Divakaran,

    Regarding the UART Interrupt I am not sure I understand your question. 
    You want to receive via UART a X number of bytes, and you want an interrupt to occur when you start receiving. Have I misunderstood something?
    I would recommend checking the 14.2 Architecture, page: 106 on DA14531 Datasheet
    Especially 14.2.3-14.2.4-14.2.5 and 14.3.
    And the Tables 348 up to 354 on page:292 which are the UART Interface Registers.

    In da145xx.h file you can find the Interrupt Requests available on SDK:

    /*
    * -----------------------------------------------------------------------------------------------
    * The Cortex-M0+ Processor Exceptions Numbers and Device Specific Interrupt Request Numbers.    -
    * -----------------------------------------------------------------------------------------------
    */
    typedef enum IRQn
    {
    /****** Cortex-M0+ Processor Exceptions Numbers ************************************************/
    NonMaskableInt_IRQn  = -14, /*  2 Non Maskable Interrupt Request.                              */
    HardFault_IRQn       = -13, /*  3 Cortex-M0 Hard Fault Interrupt Request.                      */
    SVCall_IRQn          = -5,  /* 11 Cortex-M0 SV Call Interrupt Request.                         */
    PendSV_IRQn          = -2,  /* 14 Cortex-M0 Pend SV Interrupt Request.                         */
    SysTick_IRQn         = -1,  /* 15 Cortex-M0 System Tick Interrupt Request.                     */
    
    /****** D2632 Specific Interrupt Numbers *******************************************************/
    BLE_WAKEUP_LP_IRQn   =  0,  /* Wakeup from Low Power Interrupt Request from BLE.               */
    BLE_GEN_IRQn         =  1,  /* BLE Interrupt Request. Sources:                                 */
                                /*   - finetgtim_irq  : Fine Target Timer interrupt generated when */
                                /*                      Fine Target timer expired. Timer           */
                                /*                      resolution is 625us base time reference.   */
                                /*   - grosstgtim_irq : Gross Target Timer interrupt generated     */
                                /*                      when Gross Target timer expired. Timer     */
                                /*                      resolution is 16 times 625us base time     */
                                /*                      reference.                                 */
                                /*   - cscnt_irq      : 625us base time reference interrupt,       */
                                /*                      available in active modes.                 */
                                /*   - slp_irq        : End of Sleep mode interrupt.               */
                                /*   - error_irq      : Error interrupt, generated when undesired  */
                                /*                      behavior or bad programming occurs in the  */
                                /*                      BLE Core.                                  */
                                /*   - rx_irq         : Receipt interrupt at the end of each       */
                                /*                      received packets.                          */
                                /*   - event_irq      : End of Advertising / Scanning / Connection */
                                /*                      events interrupt.                          */
                                /*   - crypt_irq      : Encryption / Decryption interrupt,         */
                                /*                      generated either when AES and/or CCM       */
                                /*                      processing is finished.                    */
                                /*   - sw_irq         : SW triggered interrupt, generated on SW    */
                                /*                      request.                                   */
    UART_IRQn            =  2,  /* UART Interrupt Request.                                         */
    UART2_IRQn           =  3,  /* UART2 Interrupt Request.                                        */
    I2C_IRQn             =  4,  /* I2C Interrupt Request.                                          */
    SPI_IRQn             =  5,  /* SPI Interrupt Request.                                          */
    ADC_IRQn             =  6,  /* Analog-Digital Converter Interrupt Request.                     */
    KEYBRD_IRQn          =  7,  /* Keyboard Interrupt Request.                                     */
    BLE_RF_DIAG_IRQn     =  8,  /* Baseband or Radio Diagnostics Interrupt Request. Required for   */
                                /* signaling Radio or Baseband internal events.                    */
                                /* 2 signals per Radio and 2 per BB                                */
    RF_CAL_IRQn          =  9,  /* Radio Calibration Interrupt Request.                            */
    GPIO0_IRQn           = 10,  /* GPIO Interrupt Request through debounce.                        */
    GPIO1_IRQn           = 11,  /* GPIO Interrupt Request through debounce.                        */
    GPIO2_IRQn           = 12,  /* GPIO Interrupt Request through debounce.                        */
    GPIO3_IRQn           = 13,  /* GPIO Interrupt Request through debounce.                        */
    GPIO4_IRQn           = 14,  /* GPIO Interrupt Request through debounce.                        */
    SWTIM_IRQn           = 15,  /* Software Timer (Timer0) Interrupt Request.                      */
    WKUP_QUADEC_IRQn     = 16,  /* Combines the Wake up Capture Timer Interrupt Request,           */
                                /* the GPIO Interrupt and the QuadDecoder Interrupt Request.       */
    SWTIM1_IRQn          = 17,  /* Software Timer (Timer1) Interrupt Request.                      */
    RTC_IRQn             = 18,  /* RTC Alarm Interrupt Request.                                    */
    DMA_IRQn             = 19,  /* DMA Interrupt Request.                                          */
    XTAL32M_RDY_IRQn     = 20,  /* XTAL 32M settling Interrupt Request.                            */
    RESERVED21_IRQn      = 21,  /* SoftWare Interrupt Request.                                     */
    RESERVED22_IRQn      = 22,  /* SoftWare Interrupt Request.                                     */
    RESERVED23_IRQn      = 23,  /* SoftWare Interrupt Request.                                     */
    } IRQn_Type;

    You should configure IRQ for UART/UART2. Inside gpio.h you can find the functions you will need to achieve that:

    /*
     * FUNCTION DECLARATIONS
     ****************************************************************************************
     */
    
    /**
     ****************************************************************************************
     * @brief Register Callback function for GPIO IRQ.
     * @param[in] irq       The handler of this IRQ will call the function
     * @param[in] callback  Callback function's reference.
     ****************************************************************************************
     */
    void GPIO_RegisterCallback(IRQn_Type irq, GPIO_handler_function_t callback);
    
    /**
     ****************************************************************************************
     * @brief Function to set the interrupt generated by the GPIO pin.
     * @param[in] port          GPIO port
     * @param[in] pin           GPIO pin
     * @param[in] irq           GPIO IRQ
     * @param[in] low_input     TRUE generates an IRQ if the input is low
     * @param[in] release_wait  TRUE waits for key release after interrupt was reset
     * @param[in] debounce_ms   duration of a debounce sequence before an IRQ is generated
     ****************************************************************************************
     */
    void GPIO_EnableIRQ(GPIO_PORT port,
                        GPIO_PIN pin,
                        IRQn_Type irq,
                        bool low_input,
                        bool release_wait,
                        uint8_t debounce_ms);
    
    
    /**
     ****************************************************************************************
     * @brief Function to reset the interrupt generated by the GPIO pin.
     * @param[in] irq   GPIO IRQ
     ****************************************************************************************
     */
    void GPIO_ResetIRQ(IRQn_Type irq);
    
    
    /**
     ****************************************************************************************
     * @brief GPIO IRQn Handler
     * @param[in] irq   The IRQ that this handler services
     ****************************************************************************************
     */
    void GPIOn_Handler(IRQn_Type irq);
    


    Regarding the uart_receive function inside uart.c file:
    void uart_receive(uart_t *uart_id, uint8_t *data, uint16_t len, UART_OP_CFG op)
    {
        uart_env_t *uart_env = UART_ENV(uart_id);
    
        // Initialize UART environment
        uart_env->rx_total_length = len;
        uart_env->rx_index = 0;
        // Save starting address of data in environment
        uart_env->rx_buffer = data;
    
        // Blocking receive procedure
        if (op == UART_OP_BLOCKING)
        {
            uart_read_buffer(uart_id, data, len);
        }
        else if (op == UART_OP_INTR)
        {
            // Disable NVIC interrupts
            NVIC_DisableIRQ(UART_INTR(uart_id));
    
            // Enable receive interrupts
            uart_rxdata_intr_setf(uart_id, UART_BIT_EN);
            uart_rls_intr_setf(uart_id, UART_BIT_EN);
    
            // Enable interrupt priority
            NVIC_SetPriority(UART_INTR(uart_id), uart_env->intr_priority);
            // Enable NVIC interrupts
            NVIC_EnableIRQ(UART_INTR(uart_id));
        }

    As you can see it enables the UART Interrupt inside, and you can give the variable len as input for the length of the message you are expecting.

    Kind Regards,
    OV_Renesas

  • Hi,

    I was referring to the same code. 
    But my concern is that, in the code segment for UART Receive below:

                    // Initialize UART environment
                      uart_env->rx_total_length = len;

    I cannot pre define the length, because as per my requirement, I have to receive from UART till a delimiter or End of Packet byte is received.

    Thanks Again.

  • Hi Divakaran,

    I think I understand your question now. 
    So, each time you want to receive something it will not have a fixed length?
    If you know the max size that you want to receive, you can set the length to that and after receiving you can check the last byte if it is a delimiter or End of Packet.
    You could also work with uart_read_byte function:

    uint8_t uart_read_byte(uart_t *uart_id)
    {
        // Wait until received data are available
        while (!uart_data_ready_getf(uart_id));
    
        // Read element from the receive FIFO
        return uart_read_rbr(uart_id);
    }

    I suppose that you want to call this inside the write handler, which might cause some problems since there is not a definite time of waiting. You can implement your own function which will use a timer to check every 1second if you have received the value you want. And when you read a delimiter or End of Packet byte you could stop the procedure.

    Kind Regards,
    OV_Renesas

  • Thank you for the reply,

    This was exactly my question. I think the solution you provided is fine and will be working.
    Just had one more doubt in my project in the case of the APP Receiving the response back from the BLE device (the data which we received from UART Receive).

    I thought of using the notify operation, so that on data being received on the device, notify can be used to send it across to the App. So should I write a custom function in the 'user_custs1_impl.c' source file for the notify operation. Could you provide some example code for the above scenario as I am not sure on the code?

    Thank you,
    Divakaran