nrf52805: ADC polling mode issue

Hardware setup: Custom board using BC805M-P (with App protect)
Software: nrf5 SDK S112 v17.0.2 ->Segger V7.30

My Objective: 

measure the Li-ion battery voltage(4.2V -100% till 3.6V-0%) through an external resistive divider & internal 0.6v ref voltage. (I'm not worried about the current consumption as of this moment. would like to make this concept work & all the other optimisations shall see later. Regarding optimisations yes I'm aware of this page: https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/measuring-lithium-battery-voltage-with-nrf52)

What works so far?
for the moment my example measured voltage value is being transmitted over BLE through the battery service. it's all working well.
But the ADC is just measuring some garbage value (random) which is clearly not correct.

My concept of ADC polling mode is taken from this post & modified for my work. https://devzone.nordicsemi.com/f/nordic-q-a/14486/measuring-the-battery-voltage-with-nrf52832/129422

// Input range of External Vdd measurement = (0.6 V)/(1/5) = 3 V
// 3.0 volts ->  16383 ADC counts with 14-bit sampling:  5461 counts per volt
// 3.0 volts ->  4095 ADC counts with 12-bit sampling:  1365 counts per volt

#define ADC12_COUNTS_PER_VOLT 5461

void Adc12bitPolledInitialise(void)
{
    uint32_t timeout = 10;
    nrf_saadc_channel_config_t myConfig =
    {
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
        .gain       = NRF_SAADC_GAIN1_5,            // (1/5) Gain
        .reference  = NRF_SAADC_REFERENCE_INTERNAL, // 0.6V internal Ref Voltage
        .acq_time   = NRF_SAADC_ACQTIME_40US,       // See max source resistancetable
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,
        .burst      = NRF_SAADC_BURST_DISABLED,
        .pin_p      = NRF_SAADC_INPUT_AIN2,         // AIN2 for input Pin
        .pin_n      = NRF_SAADC_INPUT_DISABLED
    };

    nrf_saadc_resolution_set((nrf_saadc_resolution_t) 3);   // 2 is 12-bit , 3 for 14-bit 
    nrf_saadc_oversample_set((nrf_saadc_oversample_t) 2);   // 2 is 4x, about 150uSecs total
    nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
    nrf_saadc_enable();

    NRF_SAADC->CH[1].CONFIG =
              ((myConfig.resistor_p << SAADC_CH_CONFIG_RESP_Pos)   & SAADC_CH_CONFIG_RESP_Msk)
            | ((myConfig.resistor_n << SAADC_CH_CONFIG_RESN_Pos)   & SAADC_CH_CONFIG_RESN_Msk)
            | ((myConfig.gain       << SAADC_CH_CONFIG_GAIN_Pos)   & SAADC_CH_CONFIG_GAIN_Msk)
            | ((myConfig.reference  << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
            | ((myConfig.acq_time   << SAADC_CH_CONFIG_TACQ_Pos)   & SAADC_CH_CONFIG_TACQ_Msk)
            | ((myConfig.mode       << SAADC_CH_CONFIG_MODE_Pos)   & SAADC_CH_CONFIG_MODE_Msk)
            | ((myConfig.burst      << SAADC_CH_CONFIG_BURST_Pos)  & SAADC_CH_CONFIG_BURST_Msk);

    NRF_SAADC->CH[1].PSELN = myConfig.pin_n;
    NRF_SAADC->CH[1].PSELP = myConfig.pin_p;
}

void ble_Update_BatteryVoltage(void)
{
    // Enable command & Turn on the Power
    nrf_gpio_pin_write(ADC_SWITCH, 1); //turning on the voltage bridge on with a transistor
    nrf_saadc_enable();

    uint16_t result = 9999;         // Some recognisable dummy value
    uint32_t timeout = 100000;       // Trial and error
    volatile int16_t buffer[8];

    NRF_SAADC->RESULT.PTR = (uint32_t)buffer;
    NRF_SAADC->RESULT.MAXCNT = 1;

    nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
    nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
    nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);

    if (timeout != 0)
    {
        result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/
        5)) / ADC12_COUNTS_PER_VOLT;
    }

    while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
    {
        timeout--;
    }
    nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_END);

    // Disable command & turn off the Power to ADC Bridge to reduce power consumption
    nrf_saadc_disable();
    
    nrf_gpio_pin_write(ADC_SWITCH, 0); //turning off the voltage bridge on with a transistor
    ble_bas_battery_level_update(&m_bas, result, m_conn_handle); 
}


The ADC result value is clearly not accurately working when I'm just calling the function manually upon a button press. ble_Update_BatteryVoltage();

What am I doing wrong?

Thanks, for any valuable input I'm new to NRF. 
Gokunath 

Parents
  • Hi Gokulnath,

    My Objective: 

    measure the Li-ion battery voltage(4.2V -100% till 3.6V-0%) through an external resistive divider & internal 0.6v ref voltage. (I'm not worried about the current consumption as of this moment. would like to make this concept work & all the other optimisations shall see later

    You could try the peripheral/saadc sample in nRF5 SDK.

    But the ADC is just measuring some garbage value (random) which is clearly not correct.

    What does this look like? Would you be able to provide an example? Does the this change if you change the voltage?

    Thanks, for any valuable input I'm new to NRF. 

    nRF Connect SDK is recommended for new designs. Please see the nRF Connect SDK and nRF5 SDK statement as well as the nRF Connect SDK Fundamentals course at Nordic Developer Academy.

    https://www.nordicsemi.com/Products/Development-software/nrf-connect-sdk

    Here are some samples for nRF Connect SDK. You could start with simple_blocking or simple_nonblocking: hal_nordic/nrfx/samples/src/nrfx_saadc at master · zephyrproject-rtos/hal_nordic · GitHub

  • There is a bug here, the result is read before the SAADC sample has completed:

        if (timeout != 0)
        {
            result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/
            5)) / ADC12_COUNTS_PER_VOLT;
        }
    
        while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
        {
            timeout--;
        }

    Change to:

        while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
        {
            timeout--;
        }
        if (timeout != 0)
        {
            result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/
            5)) / ADC12_COUNTS_PER_VOLT;
        }

  • Hi Gokulnath, sorry for the long delay.

    What are the reslults from your lateste updated code?

    Anyways, looking over this thread, somthing that seems to be missing is the wait for the SAADC to be ready, by checking for the NRF_SAADC_EVENT_STARTED event. By adding a check for the NRF_SAADC_EVENT_STARTED event before initiating sampling, you can ensure that the ADC has fully powered up and stabilized:

    // Start the SAADC to prepare for sampling
    nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
    
    // Wait until the SAADC is ready (EVENT_STARTED is set)
    while (!nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED)) {
        // Optionally, you could add a timeout mechanism here to avoid waiting indefinitely
    }
    
    // Clear the STARTED event to enable detection next time
    nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
    
    // Trigger the SAADC to take a sample now that it is ready
    nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);

  • By making a tiny change and masking out some of your code the raw SAADC results look ok to me without using bust mode or averaging or filtering (using 931k and 200k, so similar):

    Battery 2984
    Battery 2982
    Battery 2966
    Battery 2969
    Battery 2973
    Battery 2964
    Battery 2965
    Battery 2970
    Battery 2968
    Battery 2960
    Battery 2960
    Battery 2958
    Battery 2966
    Battery 2961
    Battery 2960
    Battery 2965
    Battery 2970

    I made these simple changes:

        .gain       = NRF_SAADC_GAIN1, // Gain (was 1.5)
    
        volatile int16_t buffer[20]; // 16-bit signed, not 32-bit signed

    I commented out the maths and added a print:

        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        // Add a printout to test raw data
        char InfoPacket[120] = "";
        snprintf(InfoPacket, sizeof(InfoPacket), "Battery %4d\r\n", result);
        uartSend(InfoPacket, strlen(InfoPacket));
        // Remove the odd maths stuff, that's a non-SAADC issue
    //  while(result>100 && result >0)
    //  {
    //  result = result%100;
    //  }
    //  if(Old_Bat != result && result >=1 && result !=0)
    //  {
    //  if(result<=17)
    //  {
    //  result = 5;
    //  nrf_gpio_pin_write(BLUE_LED, 0); //Turning on the LOW BAttery Flash LED
    //  nrf_delay_ms(1000); // add a delay to make the capacitor charge
    //  nrf_gpio_pin_write(BLUE_LED, 1); //Turning off the LOW BAttery Flash LED
    //  }
    //  Old_Bat = result;
    //  ble_bas_battery_level_update(&m_bas, result, m_conn_handle);
    //  }
    }
    

  • Hey  
    Could you precise your ADC Config? more precisely the ADC reference Voltage?

    also, question on this:
    from Datasheet of nrf52805: 


    My implemented formula: (for gain 1.5 & 0.6V REF Voltage for the above voltage divider of 220K & 36K? on a 4.2V Battery)
    result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/2)) / ADC12_COUNTS_PER_VOLT;

    is the above correct? I think my gain might be incorrect!  where My Desired Battery voltage range is this: 4.2V 100% => 3.63V 0%

    or should it be like this? (for gain 1 & 0.6V REF Voltage for the above voltage divider of 220K & 36K? on a 4.2V Battery )
    result = ((buffer[0] * 1000L) * 1.667 * 16384);

    Vadc= Vbat * ((360K)/(360K+2M2)) => Vadc = Vbat * 0.140625

    // Input range of internal Vdd measurement = (0.6 V)/(1) = 0.6 V MAX in External Resistor Divider Output.
    // 16384 ADC counts with 14-bit sampling:  0.1v = 2730.6 ADC Counts
    // Resistor Divider 2.2M & 360K
    // 4.2V  => 0.591 volts -> Assuming 100% Battery SoC
    // 3.63V => 0.51 Volts -> Assuming 0% Battery SoC
    // 
    
    
    if (timeout != 0)
        {
            //result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/2)) / ADC12_COUNTS_PER_VOLT;
            result = (float)((buffer[0] * 1000L) * 1.667 * 16384);
            result = result/0.140625;
            result = volttopercent(result);
        }
        
        float volttopercent(float vadc)
    {
      float Vmax = 4.2;
      float Vmin = 3.63;
      
      float percentage;
    
      percentage = ((vadc -Vmin)/(Vmax - Vmin))*100;
    
      return percentage;
    }
    
    // NOW RESULT SHOULD send VBat in terms of custom % ?


    I'm using the internal chip 0.6V.  I shall do the test on my side with this added info & shall post the results here. 

    *******************************************************************************************************************************
    See the below thread too for my reply to Helsing

    Thanks.
    Gokulnath A R

  • Hey  ,
    Thanks for the suggestion I've also added the calibration too..

    my new code below along with my New Hardware. But i have a few questions so asked them below (next thread) 

    // Input range of internal Vdd measurement = (0.6 V)/(1) = 0.6 V MAX in External Resistor Divider Output.
    // 16384 ADC counts with 14-bit sampling:  0.1v = 2730.6 ADC Counts
    // Resistor Divider 2.2M & 360K
    // 4.2V  => 0.591 volts -> Assuming 100% Battery SoC
    // 3.63V => 0.51 Volts -> Assuming 0% Battery SoC
    //  Vadc= Vbat * ((360K)/(360K+2M2)) => Vadc = Vbat * 0.140625
    
    void Adc12bitPolledInitialise(void)
    {
        uint32_t timeout = 10;
        nrf_saadc_channel_config_t myConfig =
        {
            .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
            .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
            .gain       = NRF_SAADC_GAIN1,              //  1 Gain
            .reference  = NRF_SAADC_REFERENCE_INTERNAL, // 0.6V internal Ref Voltage
            .acq_time   = NRF_SAADC_ACQTIME_40US,       // See max source resistancetable
            .mode       = NRF_SAADC_MODE_SINGLE_ENDED,
            .burst      = NRF_SAADC_BURST_DISABLED,
            .pin_p      = NRF_SAADC_INPUT_AIN3,         // AIN3 for input Pin
            .pin_n      = NRF_SAADC_INPUT_DISABLED
        };
    
        nrf_saadc_resolution_set((nrf_saadc_resolution_t) 3);   // 2 is 12-bit , 3 for 14-bit 
        //nrf_saadc_oversample_set((nrf_saadc_oversample_t) 2);   // 2 is 4x, about 150uSecs total
        nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        nrf_saadc_enable();
    
        NRF_SAADC->CH[1].CONFIG =
                  ((myConfig.resistor_p << SAADC_CH_CONFIG_RESP_Pos)   & SAADC_CH_CONFIG_RESP_Msk)
                | ((myConfig.resistor_n << SAADC_CH_CONFIG_RESN_Pos)   & SAADC_CH_CONFIG_RESN_Msk)
                | ((myConfig.gain       << SAADC_CH_CONFIG_GAIN_Pos)   & SAADC_CH_CONFIG_GAIN_Msk)
                | ((myConfig.reference  << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
                | ((myConfig.acq_time   << SAADC_CH_CONFIG_TACQ_Pos)   & SAADC_CH_CONFIG_TACQ_Msk)
                | ((myConfig.mode       << SAADC_CH_CONFIG_MODE_Pos)   & SAADC_CH_CONFIG_MODE_Msk)
                | ((myConfig.burst      << SAADC_CH_CONFIG_BURST_Pos)  & SAADC_CH_CONFIG_BURST_Msk);
    
        NRF_SAADC->CH[1].PSELN = myConfig.pin_n;
        NRF_SAADC->CH[1].PSELP = myConfig.pin_p;
    }
    
    void ble_Update_BatteryVoltage(void)
    {
        nrf_saadc_enable();
    
        nrf_delay_ms(100); // add a delay to make the capacitor charge 
    
        volatile float result = 0;              // Some recognisable dummy value
        uint32_t timeout = 1000000;       // Trial and error
        volatile int32_t buffer[10];
    
        NRF_SAADC->RESULT.PTR = (uint32_t)buffer;
        NRF_SAADC->RESULT.MAXCNT = 1;
    
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        nrf_saadc_task_trigger(NRF_SAADC_TASK_START);   // Start the SAADC to prepare for sampling
    
        // Wait until the SAADC is ready (EVENT_STARTED is set)
        while (!nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED) && !nrf_saadc_event_check(NRF_SAADC_EVENT_CALIBRATEDONE)) 
        {
            // Optionally, you could add a timeout mechanism here to avoid waiting indefinitely
        }
    
        nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);  // Trigger the SAADC to take a sample now that it is ready
    
        while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
        {
            timeout--;
        }
    
        if (timeout != 0)
        {
            //result = ((buffer[0] * 1000L)+(ADC12_COUNTS_PER_VOLT/2)) / ADC12_COUNTS_PER_VOLT;
            result = (float)((buffer[0] * 1000L) * 1.667 * 16384);
            result = result/0.140625;
            result = volttopercent(result);
        }
    
        nrf_saadc_disable();
    
        nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);  // Clear the STARTED event to enable detection next time
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        
        /*
        while(result>100 && result >0)
        {
        result = result%100;
        }
        */
             
        if(Old_Bat != result && result >=1 && result !=0)
        {
    
        if(result<=5)
        {
        //result = 5;
        nrf_gpio_pin_write(BLUE_LED, 0); //Turning on the LOW BAttery Flash LED
        nrf_delay_ms(1000); // add a delay to make the capacitor charge 
        nrf_gpio_pin_write(BLUE_LED, 1); //Turning off the LOW BAttery Flash LED   
        }
        
        Old_Bat = result;
        ble_bas_battery_level_update(&m_bas, result, m_conn_handle);
        }
        nrf_saadc_task_trigger(NRF_SAADC_TASK_CALIBRATEOFFSET);
    }
    
    float volttopercent(float vadc)
    {
      float Vmax = 4.2;
      float Vmin = 3.63;
      
      float percentage;
    
      percentage = ((vadc -Vmin)/(Vmax - Vmin))*100;
    
      return percentage;
    }


    I'm still testing it so dont know the results 100% yet.
    Thanks 

  • Using the code posted with the floating-point percentage calculation: This data comes from your code using a 2.996 volt input (slightly different resistors, but that is not the point here):

    -Raw SAADC-   --------Scaled-------   --------Percent1-----    -------Percent2-----
     Dec   Hex     Decimal     Hex         Decimal      Hex         Decimal      Hex
    ==== ======   ========== ==========   ========== ==========    ========== ==========
    2979 0x0BA3    2979.00   0x453A3000      39.86  0x421F6DB7       39.86 0x421F6DB7
    2972 0x0B9C    2972.00   0x4539C000      38.86  0x421B6DB7       38.86 0x421B6DB7
    2965 0x0B95    2965.00   0x45395000      37.86  0x42176DB7       37.86 0x42176DB7
    2964 0x0B94    2964.00   0x45394000      37.71  0x4216DB6D       37.71 0x4216DB6D
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    with Burst 4 enabled
    2981 0x0BA5    2981.00   0x453A5000      40.14  0x42209249       40.14 0x42209249
    2970 0x0B9A    2970.00   0x4539A000      38.57  0x421A4925       38.57 0x421A4925
    2972 0x0B9C    2972.00   0x4539C000      38.86  0x421B6DB7       38.86 0x421B6DB7
    2965 0x0B95    2965.00   0x45395000      37.86  0x42176DB7       37.86 0x42176DB7
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    

    ints truncate floats; also as an aside floats (on the nRF52 hardware) are only 32-bit inclusive of sign and exponent, so have less precision than 32-bit ints. Compiler implicit conversion is compiler-dependent.

    The data above is generated by adding these lines to the code :

    // Input range = (0.6 V)/(1)   = 0.6V -> 3.393 V with 931k/200K dividers
    // 3.0 volts -> 14486 ADC counts with 14-bit sampling: 4828.8 counts per volt
    #define ADC12_COUNTS_PER_VOLT 4829
    
        // Disable command & turn off the Power to ADC Bridge to reduce power consumption
        nrf_gpio_pin_write(ADC_SWITCH, 0); //Turning off the voltage divider transistor
        nrf_saadc_disable();
        nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        float f_result = (float)((buffer[0] * 1000L) * 1.667 * 16384);
        f_result = result; ///0.140625;
        int32_t i_result = result; ///0.140625;
        float percent_result1 = volttopercent(i_result);
        float percent_result2 = volttopercent(f_result);
        char InfoPacket[180] = "";
        // -Raw SAADC-   -------Scaled-----   ------Percent1----   ------Percent2----
        //  Dec   Hex    Decimal   Hex        Decimal     Hex      Decimal    Hex
        // ==== ======   ======= ==========   ======= ==========   ======= ==========
        // 2968 0x0B98   2968.00 0x45398000     38.29 0x42192492     38.29 0x42192492
        snprintf(InfoPacket, sizeof(InfoPacket), "-Raw SAADC-   -------Scaled-----   ------Percent1----   ------Percent2----\r\n");  uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), " Dec   Hex    Decimal   Hex        Decimal     Hex      Decimal    Hex\r\n");     uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), "==== ======   ======= ==========   ======= ==========   ======= ==========\r\n"); uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), "%4d 0x%04X  %8.2f 0x%08X    %6.2f 0x%08X    %6.2f 0x%08X\r\n", result, result, f_result, *(uint32_t *)&f_result, percent_result1, *(uint32_t *)&percent_result1, percent_result2, *(uint32_t *)&percent_result2);
        uartSend(InfoPacket, strlen(InfoPacket));

    My post here is to show how to check the algorithm is doing the required actions ..

    Edit: I commented out the peculiar 0.140625 divider, correctd the hex float print and changed the % calc to use mV and correct min & max for my test setup

Reply
  • Using the code posted with the floating-point percentage calculation: This data comes from your code using a 2.996 volt input (slightly different resistors, but that is not the point here):

    -Raw SAADC-   --------Scaled-------   --------Percent1-----    -------Percent2-----
     Dec   Hex     Decimal     Hex         Decimal      Hex         Decimal      Hex
    ==== ======   ========== ==========   ========== ==========    ========== ==========
    2979 0x0BA3    2979.00   0x453A3000      39.86  0x421F6DB7       39.86 0x421F6DB7
    2972 0x0B9C    2972.00   0x4539C000      38.86  0x421B6DB7       38.86 0x421B6DB7
    2965 0x0B95    2965.00   0x45395000      37.86  0x42176DB7       37.86 0x42176DB7
    2964 0x0B94    2964.00   0x45394000      37.71  0x4216DB6D       37.71 0x4216DB6D
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    with Burst 4 enabled
    2981 0x0BA5    2981.00   0x453A5000      40.14  0x42209249       40.14 0x42209249
    2970 0x0B9A    2970.00   0x4539A000      38.57  0x421A4925       38.57 0x421A4925
    2972 0x0B9C    2972.00   0x4539C000      38.86  0x421B6DB7       38.86 0x421B6DB7
    2965 0x0B95    2965.00   0x45395000      37.86  0x42176DB7       37.86 0x42176DB7
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    2966 0x0B96    2966.00   0x45396000      38.00  0x42180000       38.00 0x42180000
    

    ints truncate floats; also as an aside floats (on the nRF52 hardware) are only 32-bit inclusive of sign and exponent, so have less precision than 32-bit ints. Compiler implicit conversion is compiler-dependent.

    The data above is generated by adding these lines to the code :

    // Input range = (0.6 V)/(1)   = 0.6V -> 3.393 V with 931k/200K dividers
    // 3.0 volts -> 14486 ADC counts with 14-bit sampling: 4828.8 counts per volt
    #define ADC12_COUNTS_PER_VOLT 4829
    
        // Disable command & turn off the Power to ADC Bridge to reduce power consumption
        nrf_gpio_pin_write(ADC_SWITCH, 0); //Turning off the voltage divider transistor
        nrf_saadc_disable();
        nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        float f_result = (float)((buffer[0] * 1000L) * 1.667 * 16384);
        f_result = result; ///0.140625;
        int32_t i_result = result; ///0.140625;
        float percent_result1 = volttopercent(i_result);
        float percent_result2 = volttopercent(f_result);
        char InfoPacket[180] = "";
        // -Raw SAADC-   -------Scaled-----   ------Percent1----   ------Percent2----
        //  Dec   Hex    Decimal   Hex        Decimal     Hex      Decimal    Hex
        // ==== ======   ======= ==========   ======= ==========   ======= ==========
        // 2968 0x0B98   2968.00 0x45398000     38.29 0x42192492     38.29 0x42192492
        snprintf(InfoPacket, sizeof(InfoPacket), "-Raw SAADC-   -------Scaled-----   ------Percent1----   ------Percent2----\r\n");  uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), " Dec   Hex    Decimal   Hex        Decimal     Hex      Decimal    Hex\r\n");     uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), "==== ======   ======= ==========   ======= ==========   ======= ==========\r\n"); uartSend(InfoPacket, strlen(InfoPacket));
        snprintf(InfoPacket, sizeof(InfoPacket), "%4d 0x%04X  %8.2f 0x%08X    %6.2f 0x%08X    %6.2f 0x%08X\r\n", result, result, f_result, *(uint32_t *)&f_result, percent_result1, *(uint32_t *)&percent_result1, percent_result2, *(uint32_t *)&percent_result2);
        uartSend(InfoPacket, strlen(InfoPacket));

    My post here is to show how to check the algorithm is doing the required actions ..

    Edit: I commented out the peculiar 0.140625 divider, correctd the hex float print and changed the % calc to use mV and correct min & max for my test setup

Children
No Data
Related