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