This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

wrong values after connecting over BLE

Hello,

I want to transfer analog values via BLE to a external Device. The SAADC is initialize for 2 channels, triggered by RTC-timer and i've get the right values from both channels. When i connect over BLE, the values i get change from ~12000 inc to ~9000 inc (14 bit resolution). Also after disconnecting the values are wrong until i restart the nrf.

My suppostion is a wrong Ramtable in Segger Studio, i have to change NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE, NRF_SDH_BLE_VS_UUID_COUNT

// <o> NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE - Attribute Table size in bytes. The size must be a multiple of 4. 
#ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE
#define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1900
#endif

// <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs. 
#ifndef NRF_SDH_BLE_VS_UUID_COUNT
#define NRF_SDH_BLE_VS_UUID_COUNT 20
#endif

in sdk_config.h and RAM_START=0x200026b8, RAM_SIZE=0xd948, because i have over 15 characteristics.

But when i read the softdevice spec, it must to be enough reserved ram.

SDK 15.3.0
Softdevice 6.1.1

Parents
  • Hi,

    When i connect over BLE, the values i get change from ~12000 inc to ~9000 inc (14 bit resolution). Also after disconnecting the values are wrong until i restart the nrf.

    Where do you check this? At the external device end or at the nRF? Could you show more of your code? 

    regards

    Jared 

  • Hello Jared,

    i have check this on the nRF (see code line 215). Channel 1 is for battery voltage and at the second channel i use a MUX to get 4 values of force. I have checked my code without MUX and lower sample rate with the same result.

    #include "saadc.h"
    #include "hbconf.h"
    #include "gyro.h"
    #include "nrf.h"
    #include "nrf_drv_clock.h"
    #include "nrf_drv_rtc.h"
    
    #define SAMPLES_IN_BUFFER ADC_AKKU+ADC_DMS
    
    volatile uint8_t state = 1;
    static bool INIT = false;
    static uint8_t conf_ausbau = 0;
    static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(3);
    static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
    static nrf_ppi_channel_t     m_ppi_channel;
    uint32_t              m_adc_evt_counter;
    static uint8_t               saadc_funktion=0;
    static uint32_t tz_AKKU = 500;                                    //Aktualisierungszeit in 100ms des Akkus
    static uint32_t tz_DMS = 1;                                       //Aktualisierungszeit in 100ms des DMS
    double realNull[AnzKraftAnlage+1] = {0.0};
    double INA_Ref =990;                                       //Spannung bei 0V Brückenspannung am A2
    double El_Limit =3000;                                     //max gewünschte Spannung am A2
    double VDMS=3.0;                                           //Versorgungsspannung DMS
    double Range;                                              //nutzbarer Spannungsbereich
    double DMS_El_Range[AnzKraftAnlage+1];
    double DMS_Mech_Range[AnzKraftAnlage+1];
    double DMS_Faktor[AnzKraftAnlage+1];
    double m_MechMin[AnzKraftAnlage+1];
    double m_MechMax[AnzKraftAnlage+1];
    double m_ElMin[AnzKraftAnlage+1];
    double m_ElMax[AnzKraftAnlage+1];
    double m_Gain;
    double rohKraft = 0.00;
    double alt_akku = 0.00;
    double cal_sum=0;
    double cs[200]={0};
    int akkuMin=3000;
    int m_mux_schritt=0;
    int cal_funk=0;
    int cal_zaehler=0;
    bool cal_laeuft=false;
    bool cal_null_laeuft=false;
    nrf_ppi_channel_t saadc_buffer_swap_ppi_channel;
    
    #define RTC_FREQUENCY 1024                          //Determines the RTC frequency and prescaler
    #define RTC_CC_VALUE 8                            //Determines the RTC interrupt frequency and thereby the SAADC sampling frequency
    #define SAADC_SAMPLE_INTERVAL_MS   1             //Interval in milliseconds at which RTC times out and triggers SAADC sample task 
    
    const  nrf_drv_rtc_t           rtc = NRF_DRV_RTC_INSTANCE(2); /**< Declaring an instance of nrf_drv_rtc for RTC2. */
    static uint32_t                rtc_ticks = RTC_US_TO_TICKS(SAADC_SAMPLE_INTERVAL_MS*1000, RTC_FREQUENCY);
    
    #define DMS_SAMPLES_LEN 32
    nrf_saadc_value_t dms_samples[AnzKraftAnlage+1][DMS_SAMPLES_LEN] = {0};
    uint8_t dms_samples_next=0;
    
    //globale Variablen der ADC's die zyklisch aktualisiert werden
    uint8_t v_akku = 0;
    uint32_t v_dms[AnzKraftAnlage+1] = {0};
    
    void timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
      int i=0;                      ////DEBUG
    }
    
    void set_mux_schritt(int schritt)
    {
      m_mux_schritt=schritt;
      memset(&dms_samples, 0, SAMPLES_IN_BUFFER);
    }
    
    static void lfclk_config(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();                        //Initialize the clock source specified in the nrf_drv_config.h file, i.e. the CLOCK_CONFIG_LF_SRC constant
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
    }
    
    static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
    {
        uint32_t err_code;
    	
        if (int_type == NRF_DRV_RTC_INT_COMPARE0)
        {
            nrf_drv_saadc_sample();                                        //Trigger the SAADC SAMPLE task
    		
            err_code = nrf_drv_rtc_cc_set(&rtc, 0, rtc_ticks, true);       //Set RTC compare value. This needs to be done every time as the nrf_drv_rtc clears the compare register on every compare match
            APP_ERROR_CHECK(err_code);
            nrf_drv_rtc_counter_clear(&rtc);                               //Clear the RTC counter to start count from zero
        }
    }
    
    void saadc_sampling_event_init(void)
    {
         uint32_t err_code;
    
        //Initialize RTC instance
        nrf_drv_rtc_config_t rtc_config;
        rtc_config.prescaler = RTC_FREQ_TO_PRESCALER(RTC_FREQUENCY);
        err_code = nrf_drv_rtc_init(&rtc, &rtc_config, rtc_handler);                //Initialize the RTC with callback function rtc_handler. The rtc_handler must be implemented in this applicaiton. Passing NULL here for RTC configuration means that configuration will be taken from the sdk_config.h file.
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_rtc_cc_set(&rtc, 0, rtc_ticks, true);                    //Set RTC compare value to trigger interrupt. Configure the interrupt frequency by adjust RTC_CC_VALUE and RTC_FREQUENCY constant in top of main.c
        APP_ERROR_CHECK(err_code);
    
        //Power on RTC instance
        nrf_drv_rtc_enable(&rtc);                                                   //Enable RTC
    }
    
    void saadc_start_timer(void)
    {
      nrf_drv_timer_enable(&m_timer);
    }
    
    void saadc_stop_timer(void)
    {
      nrf_drv_timer_disable(&m_timer);
    }
    
    void saadc_sampling_event_enable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    }
    
    uint8_t get_v_akku(void)
    {
       return v_akku;
    }
    
    uint32_t get_v_dms(int index)
    {
       return v_dms[index];
    }
    
    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
      double akku_tmp, test;
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            ret_code_t err_code;
    //        saadc_stop_timer();
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    
            // Abfrage Akkuspannung
           
            if (m_adc_evt_counter % tz_AKKU==0)
            {
              switch (saadc_funktion)
              {
                //VCH_IN 5V in mV
                case 1:
                  v_akku=(uint8_t)(1650.0 / 16384.0 * p_event->data.done.p_buffer[0] / 0.167);
                  break;
    
                case 2:
                  //Berechnung des Ladestroms in % (100%=300mA)
                  v_akku=(uint8_t)((1650.0 / 16384.0 * p_event->data.done.p_buffer[0])/2.632*1/3);       //0.002632V entspricht 1mA Ladestrom
                  int z=v_akku;
                  break;
    
                case 3:
                  test=p_event->data.done.p_buffer[0];
                  akku_tmp=((( p_event->data.done.p_buffer[0] / 16384.0 * 1650.0 / 0.272)-akkuMin)/1110.0*100);
                  alt_akku=(akku_tmp*0.3+ alt_akku*0.7);
                  v_akku=(uint8_t) alt_akku;
                  if (v_akku>100)
                    v_akku=100;
                  if (v_akku<0)
                    v_akku=0;
                  break;
    
                case 4:
                  v_akku=(uint8_t)(420.0 / 16384.0 * p_event->data.done.p_buffer[0]);
                  break;
    
                case 5:
                  v_akku=(uint8_t)(420.0 / 16384.0 * p_event->data.done.p_buffer[0]);
                  break;
    
                case 6:
                  v_akku=(uint8_t)(420.0 / 16384.0 * p_event->data.done.p_buffer[0]);
                  break;
    
                default:
                  v_akku=0;
                  break;
              }
            }
           
            
            double dms_avg = 0.0;
            double mw=0;
            int i=0;
            if (m_adc_evt_counter % tz_DMS==0)
            {
              dms_samples[m_mux_schritt][dms_samples_next] = p_event->data.done.p_buffer[1];
              if (dms_samples_next == DMS_SAMPLES_LEN-1) dms_samples_next=0; else dms_samples_next++;
              
              for (i=0;i<DMS_SAMPLES_LEN;i++)
              {
                dms_avg += dms_samples[m_mux_schritt][i];
              }
              dms_avg/=DMS_SAMPLES_LEN;
    
              if (m_mux_schritt<AnzahlKraftCh)                                 //Kraftsensor
              {
                rohKraft=1650.0/16384.0*dms_avg;                            // 14 bit resolution  1.65V / 2^14bits * increments= Value in mV
                mw=(rohKraft-realNull[m_mux_schritt])/((m_ElMax[m_mux_schritt]-m_ElMin[m_mux_schritt])*m_Gain)*(DMS_Mech_Range[m_mux_schritt]*1000.0)*1.0389;
                v_dms[m_mux_schritt]=mw*0.05+ v_dms[m_mux_schritt]*0.95;
                //v_dms[m_mux_schritt]=rohKraft;              /////DEBUG
    
                if(m_adc_evt_counter % 1 == 0)
                {
                  SEGGER_RTT_printf(0,"Kraft=%d   Anlage1=%d    Anlage2=%d    Anlage3=%d\n", (int)rohKraft, (int)get_v_dms(1), (int)get_v_dms(2), (int)get_v_dms(3));
                }
              }
              else                                                             //Anlagesensor
              {
                v_dms[m_mux_schritt]=dms_avg*0.05+v_dms[m_mux_schritt]*0.95;
              }
            }
    
        }
        
        if (m_adc_evt_counter>=1000)
        {
          m_adc_evt_counter=0;
        }
        else
        {
          m_adc_evt_counter++;
        }
    }
    
    void saadc_init(uint8_t variante)
    {
      conf_ausbau = conf_ausbau | variante;
      if (INIT !=true)
      {
        ret_code_t err_code;
      
      //Init Analogeingang Akku
        nrf_saadc_channel_config_t channelAkku_config =
            HB_DRV_SAADC_AKKU_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
    
         //Init Analogeingang DMS
        nrf_saadc_channel_config_t channelDMS_config =
            HB_DRV_SAADC_DMS_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); 
    
        static const nrfx_saadc_config_t hb_config = NRFX_SAADC_HB_CONFIG;
           
        err_code = nrf_drv_saadc_init(&hb_config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channelAkku_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(1, &channelDMS_config);
        APP_ERROR_CHECK(err_code);
    
       err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
      APP_ERROR_CHECK(err_code);
      
        INIT=true;
      }
    
    }
    
    void saadc_start()
    {
        twi_init();                       //falls noch nicht geschehen den I2c initialisieren
        lfclk_config();                                  //Configure low frequency 32kHz clock
        saadc_sampling_event_init();                                    //Configure RTC. The RTC will generate periodic interrupts. Requires 32kHz clock to operate.
    
        saadc_init(1);                                    //Initialize and start SAADC
    }
    
    

    here my debug window after restart

    and here after connection over BLE

  • Do you observe the same if you try to measure something external from the PCB such as a voltage from a bench top supply? Also, do you do any sorts of calibration after a connection event? 

  • Sorry for the late answer, i have to do another project first. I have checked my hardware and the voltage at the analog inputs are correct. But i found out, that the buffer values are swap when i reconnect or write to a BLE characteristic. Is there any way to prevent that?

  • Hi,

    Steffen Graf said:
    But i found out, that the buffer values are swap when i reconnect or write to a BLE characteristic. Is there any way to prevent that?

    It sounds very similar to this issue. Please try the suggested solution in that thread.

    best regards

    Jared 

Reply Children
No Data
Related