BLE+ADC

Hi,

I want to read the ADC value and send it over BLE to mobile app at every 5sec, which BLE peripheral code i need to use , Please suggest asp.

Thanks in Advance

Pavan S K

Parents
  • Hi Pavan,

    Thank you for posting your question online.
    Please refer on this Tutorial:1. Introduction — DA145XX Tutorial SDK peripherals (renesas.com)
    This tutorial is based on the empty_peripheral_template example and on chapter 9 you can find information regarding the ADC on SDK6.
    Since you want to send the data every 5sec over BLE, you should implement an app_easy_timer as well. 
    Keep in mind that if you have implemented Extended Sleep Mode during your connection you will have to sample the ADC when the BLE core is active.

    Kind Regards,
    OV_Renesas

  • Hi ,

    Its only peripheral example, How to send the ADC value over BLE to mobile app. Which BLE peripheral program to use and how to add adc peripheral there. Please help to share the example program.

    T

  • Hi Pavan,

    I worked on the ble_app_peripheral example.
    The ble_app_peripheral example has by default 3 custom services with multiple custom characteristics.
    If you want more information on how you can achieve that please check this tutorial: DA145XX Tutorial Create a Custom GATT Profile — DA145XX Tutorial Create a Custom GATT Profile (renesas.com)
    In the 1st custom service, there is a characteristic with a Characteristic User Description: "Control Point" and another characteristic with a Characteristic User Description: "ADC Value 1". 
    If you write any value other than 0 on the Control Point characteristic, then a timer starts and updates the ADC Value 1 characteristic every second with an incrementing value.
    On user_custs1_impl.c 
    For the Control Point Characteristic:

    void user_svc1_ctrl_wr_ind_handler(ke_msg_id_t const msgid,
                                          struct custs1_val_write_ind const *param,
                                          ke_task_id_t const dest_id,
                                          ke_task_id_t const src_id)
    {
        uint8_t val = 0;
        memcpy(&val, &param->value[0], param->length);
    
        if (val != CUSTS1_CP_ADC_VAL1_DISABLE)
        {
            timer_used = app_easy_timer(APP_PERIPHERAL_CTRL_TIMER_DELAY, app_adcval1_timer_cb_handler);
        }
        else
        {
            if (timer_used != EASY_TIMER_INVALID_TIMER)
            {
                app_easy_timer_cancel(timer_used);
                timer_used = EASY_TIMER_INVALID_TIMER;
            }
        }
    }

    For the ADC Value 1 Characteristic:
    void app_adcval1_timer_cb_handler()
    {
        struct custs1_val_ntf_ind_req *req = KE_MSG_ALLOC_DYN(CUSTS1_VAL_NTF_REQ,
                                                              prf_get_task_from_id(TASK_ID_CUSTS1),
                                                              TASK_APP,
                                                              custs1_val_ntf_ind_req,
                                                              DEF_SVC1_ADC_VAL_1_CHAR_LEN);
    
        // ADC value to be sampled
        static uint16_t sample      __SECTION_ZERO("retention_mem_area0");
        sample = (sample <= 0xffff) ? (sample + 1) : 0;
    		
    
        //req->conhdl = app_env->conhdl;
        req->handle = SVC1_IDX_ADC_VAL_1_VAL;
        req->length = DEF_SVC1_ADC_VAL_1_CHAR_LEN;
        req->notification = true;
    		/*Change the value updated with adc_val_mv */
        memcpy(req->value, &sample, DEF_SVC1_ADC_VAL_1_CHAR_LEN);
    
        ke_msg_send(req);
    
        if (ke_state_get(TASK_APP) == APP_CONNECTED)
        {
            // Set it once again until Stop command is received in Control Characteristic
            timer_used = app_easy_timer(APP_PERIPHERAL_CTRL_TIMER_DELAY, app_adcval1_timer_cb_handler);
        }
    }

    So, following the Tutorial for GPADC I shared on my previous answer, I added the following code snippets.
    On user_periph_setup.h
    /****************************************************************************************/
    /* UART2 configuration                                                                  */
    /****************************************************************************************/
    // Define UART2 Tx Pad
    #if defined (__DA14531__)
        #define UART2_TX_PORT           GPIO_PORT_0
        #define UART2_TX_PIN            GPIO_PIN_5
    #else
        #define UART2_TX_PORT           GPIO_PORT_0
        #define UART2_TX_PIN            GPIO_PIN_4
    #endif
    
    
    #define ADC_INPUT_PORT                  GPIO_PORT_0
    #define ADC_INPUT_PIN                   GPIO_PIN_6

    On user_periph_setup.c file:
    void GPIO_reservations(void)
    {
    /*
        i.e. to reserve P0_1 as Generic Purpose I/O:
        RESERVE_GPIO(DESCRIPTIVE_NAME, GPIO_PORT_0, GPIO_PIN_1, PID_GPIO);
    */
    
    #if defined (CFG_PRINTF_UART2)
        RESERVE_GPIO(UART2_TX, UART2_TX_PORT, UART2_TX_PIN, PID_UART2_TX);
    #endif
    
        RESERVE_GPIO(LED, GPIO_LED_PORT, GPIO_LED_PIN, PID_GPIO);
    
    #if !defined (__DA14586__)
        RESERVE_GPIO(SPI_EN, SPI_EN_PORT, SPI_EN_PIN, PID_SPI_EN);
    #endif
    	RESERVE_GPIO(ADC_INPUT, ADC_INPUT_PORT, ADC_INPUT_PIN, PID_ADC);
    	
    }
    
    void set_pad_functions(void)
    {
    /*
        i.e. to set P0_1 as Generic purpose Output:
        GPIO_ConfigurePin(GPIO_PORT_0, GPIO_PIN_1, OUTPUT, PID_GPIO, false);
    */
    
    #if defined (__DA14586__)
        // Disallow spontaneous DA14586 SPI Flash wake-up
        GPIO_ConfigurePin(GPIO_PORT_2, GPIO_PIN_3, OUTPUT, PID_GPIO, true);
    #else
        // Disallow spontaneous SPI Flash wake-up
        GPIO_ConfigurePin(SPI_EN_PORT, SPI_EN_PIN, OUTPUT, PID_SPI_EN, true);
    #endif
    
    #if defined (CFG_PRINTF_UART2)
        // Configure UART2 TX Pad
        GPIO_ConfigurePin(UART2_TX_PORT, UART2_TX_PIN, OUTPUT, PID_UART2_TX, false);
    #endif
    		GPIO_ConfigurePin(ADC_INPUT_PORT, ADC_INPUT_PIN, INPUT, PID_ADC, false);
    
        GPIO_ConfigurePin(GPIO_LED_PORT, GPIO_LED_PIN, OUTPUT, PID_GPIO, false);
    }

    On user_custs1_impl.c file:
    #include "adc.h"
    #include "adc_531.h"
    #include "arch_console.h"
    
    /* According to SDK6 Peripheral Drivers Tutorial
     http://lpccs-docs.renesas.com/da145xx_tutorial_sdk6_peripherals/da14531_adc.html
    */
    static uint16_t gpadc_read(void);
    static uint16_t gpadc_sample_to_mv(uint16_t sample);
    
    static uint16_t gpadc_read(void)
    {
        /* Initialize the ADC */
        adc_config_t adc_cfg =
        {
            .input_mode = ADC_INPUT_MODE_SINGLE_ENDED,
            .input = ADC_INPUT_SE_P0_6,
            .smpl_time_mult = 2,
            .continuous = false,
            .interval_mult = 0,
            .input_attenuator = ADC_INPUT_ATTN_4X,
            .chopping = false,
            .oversampling = 0,
        };
        adc_init(&adc_cfg);
    
        /* Perform offset calibration of the ADC */
        adc_offset_calibrate(ADC_INPUT_MODE_SINGLE_ENDED);
    
        adc_start();
        uint16_t result = adc_correct_sample(adc_get_sample());
        adc_disable();
    
        return (result);
    }
    
    static uint16_t gpadc_sample_to_mv(uint16_t sample)
    {
        /* Resolution of ADC sample depends on oversampling rate */
        uint32_t adc_res = 10 + ((6 < adc_get_oversampling()) ? 6 : adc_get_oversampling());
    
        /* Reference voltage is 900mv but scale based in input attenation */
        uint32_t ref_mv = 900 * (GetBits16(GP_ADC_CTRL2_REG, GP_ADC_ATTN) + 1);
    
        return (uint16_t)((((uint32_t)sample) * ref_mv) >> adc_res);
    }

    And on the same file for the ADC Value 1 Characteristic I modified the handler as shown below:
    void app_adcval1_timer_cb_handler()
    {
        struct custs1_val_ntf_ind_req *req = KE_MSG_ALLOC_DYN(CUSTS1_VAL_NTF_REQ,
                                                              prf_get_task_from_id(TASK_ID_CUSTS1),
                                                              TASK_APP,
                                                              custs1_val_ntf_ind_req,
                                                              DEF_SVC1_ADC_VAL_1_CHAR_LEN);
    
        // ADC value to be sampled
        static uint16_t sample      __SECTION_ZERO("retention_mem_area0");
        sample = (sample <= 0xffff) ? (sample + 1) : 0;
    		
    	  /* Perform single ADC conversion */
        uint16_t result = gpadc_read();
    		/* Print the Adc Result */
        arch_printf("\n\radc result: %dmv", gpadc_sample_to_mv(result));
    		/* Save the ADC Result in a variable in order to update the characteristic */
    		uint16_t adc_val_mv = gpadc_sample_to_mv(result);
    
        //req->conhdl = app_env->conhdl;
        req->handle = SVC1_IDX_ADC_VAL_1_VAL;
        req->length = DEF_SVC1_ADC_VAL_1_CHAR_LEN;
        req->notification = true;
    		/*Change the value updated with adc_val_mv */
        memcpy(req->value, &adc_val_mv, DEF_SVC1_ADC_VAL_1_CHAR_LEN);
    
        ke_msg_send(req);
    
        if (ke_state_get(TASK_APP) == APP_CONNECTED)
        {
            // Set it once again until Stop command is received in Control Characteristic
            timer_used = app_easy_timer(APP_PERIPHERAL_CTRL_TIMER_DELAY, app_adcval1_timer_cb_handler);
        }
    }

    Then I build and run the project. When you write any value on the Control Point characteristic you should see the value of the ADC (on P0_6) being updated every 1 second on the ADC Value 1 characteristic.


    Kind Regards,
    OV_Renesas

  • Hi

    Do you have the modified ble_app_peripheral example Project to share?

    I tried to make the modifications and compile and got the following errors.

    ..\src\user_peripheral.c(326): error: #20: identifier "RX_DATAREADY" is undefined
    case RX_DATAREADY:
    ..\src\user_peripheral.c(454): warning: #167-D: argument of type "void (*)(char *)" is incompatible with parameter of type "timer_callback"
    X_timer = app_easy_timer(NOTIFICATION_DELAY / 10, user_send_uart_ntf);
    ..\src\user_peripheral.c: 2 warnings, 1 error
    compiling user_serial_interface_manager.c...
    ..\src\user_serial_interface_manager.c(46): error: #20: identifier "TX_COMPLETE" is undefined
    struct tx_complete *rsp =KE_MSG_ALLOC(TX_COMPLETE,
    ..\src\user_serial_interface_manager.c(74): warning: #167-D: argument of type "void (*)(uint16_t, const ke_msg_id_t, const struct custs1_att_info_req *, const ke_task_id_t, const ke_task_id_t)" is incompatible with parameter of type "uart_cb_t"
    uart_register_tx_cb(uart, sim_uart_send_cb);
    ..\src\user_serial_interface_manager.c(97): error: #20: identifier "RX_DATAREADY" is undefined
    struct rx_dataready *res =KE_MSG_ALLOC(RX_DATAREADY,
    ..\src\user_serial_interface_manager.c(102): error: #136: struct "custs1_att_info_req" has no field "m1"
    strcpy(res->receive_buffer_data,param->m1);
    ..\src\user_serial_interface_manager.c(123): warning: #167-D: argument of type "void (*)(uint16_t, const ke_msg_id_t, const struct custs1_att_info_req *, const ke_task_id_t, const ke_task_id_t)" is incompatible with parameter of type "uart_cb_t"
    uart_register_rx_cb(uart, sim_uart_receive_cb);
    ..\src\user_serial_interface_manager.c: 2 warnings, 3 errors

    Thanks

    Jay

  • Hi Jay,

    Thank you for your interest in our Wireless products.
    Please find attached the ble_app_peripheral_adc_characteristic.zip file which contains the project.8015.ble_app_peripheral_adc_characteristic.zip
    Keep in mind that it has been already shared on this thread as well: (+) ADC VALUES - Bluetooth Low Energy - Wireless Connectivity - Renesas Engineering Community

    Note: Keep in mind that if I remember correctly this is a project based on the SDK v6.0.16. If you are using SDK v6.0.18 or v6.0.20 you can follow the logic shown to port this into the latest versions.

    Best Regards,
    OV_Renesas

  • Hello 

    Thank you for the prompt response. The SDKI am using is 6.0.16.1144

    I am able to compile but during linking I am getting the following

    error.111 warnings generated.
    compiling user_periph_setup.c...
    linking...
    In file included from C:\Users\Jameel\AppData\Local\Temp\p2784-2:26:
    .\out_DA14531\Objects\ble_app_peripheral_531.axf: error: 'da1458x_stack_config.h' file not found
    #include "da1458x_stack_config.h"
    .\out_DA14531\Objects\ble_app_peripheral_531.axf: Error: L6636E: Pre-processor step failed for '.\..\src\config\copied_scatter_531.sct'
    .\out_DA14531\Objects\ble_app_peripheral_531.axf: Error: L6372E: Image needs at least one load region.
    Not enough information to produce a SYMDEFs file.
    Not enough information to list image symbols.
    Not enough information to list load addresses in the image map.
    Finished: 3 information, 0 warning and 2 error messages.
    ".\out_DA14531\Objects\ble_app_peripheral_531.axf" - 3 Error(s), 111 Warning(s).
    Target not created.
    Build Time Elapsed: 00:00:17

    Regards

    Jay

  • Hi Jay,

    Thank you for the reply.
    My apologies for the misinformation.
    The project shared is actually created with the SDK v6.0.18.
    I was able to use the python script to fix the paths on the SDK v6.0.18 and compile the project as expected.
    I have added the .hex file here in case you want to Flash it on your device to test it out. 
    ble_app_peripheral_531.zip
    You can follow the approach/logic of this implementation on the SDK v6.0.16 as well.
    If you have any further questions, please create a new ticket because it is easier for us to track that down.

    Best Regards,
    OV_Renesas

  • Hello

    Thanks for the hex file and I quickly uploaded it to the dev board just to test the functionality and I have the following queries.

     

    >In the 1st custom service, there is a characteristic with a Characteristic User Description: "Control Point" >and another characteristic with a Characteristic User Description: "ADC Value 1". 
    >If you write any value other than 0 on the Control Point characteristic, then a timer starts and updates the >ADC Value 1 characteristic every second with an incrementing value.

    I am able to connect and use the SmartBond and I see the 3 custom services.

    On clicking the first or 3rd service I am not able to find the control point or the ADC Value parameter is this a modified version of the original one?

Reply
  • Hello

    Thanks for the hex file and I quickly uploaded it to the dev board just to test the functionality and I have the following queries.

     

    >In the 1st custom service, there is a characteristic with a Characteristic User Description: "Control Point" >and another characteristic with a Characteristic User Description: "ADC Value 1". 
    >If you write any value other than 0 on the Control Point characteristic, then a timer starts and updates the >ADC Value 1 characteristic every second with an incrementing value.

    I am able to connect and use the SmartBond and I see the 3 custom services.

    On clicking the first or 3rd service I am not able to find the control point or the ADC Value parameter is this a modified version of the original one?

Children
  • Hello

    Please ignore my earlier post, I managed to get the ADC value in one of the attributes.

    How do we interpret this hex value of bf 02

  • Hi Jay,

    The Values shown in the SmartBond app are reversed.
    So the hex value of [bf 02] corresponds to:

    The GPADC is configured for P0_6, you will have to connect the P0_6 to some power supply to check the values given. 
    We would also suggest you open a Terminal to see the Debug Messages and the ADC result in millivolts being printed out.
    The UART pins being used are P0_5 and P0_4 and this can be seen on user_periph_setup.h file.
    For more information on the GPADC, please refer on the adc.h and adc_531.h files and also check the DA14531 Datasheet, on section 27. General Purpose ADC, on page:147.

    If you have further questions, please raise a new ticket.

    Best Regards,
    OV_Renesas