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 Reply Children
  • 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?

  • 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