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

Related