void saadc_init(void)
{
    ret_code_t err_code;
    nrf_drv_saadc_config_t saadc_config;
    nrf_saadc_channel_config_t channel_config;


	
    //Configure SAADC
    saadc_config.low_power_mode = true;                                                   //Enable low power mode.
    saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;                                 //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=2048 (when input voltage is 3.6V for channel gain setting of 1/6).
    saadc_config.oversample = SAADC_OVERSAMPLE;                                           //Set oversample to 4x. This will make the SAADC output a single averaged value when the SAMPLE task is triggered 4 times.
    saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;                               //Set SAADC interrupt to low priority.
	
    //Initialize SAADC
    err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);                         //Initialize the SAADC with configuration and callback function. The application must then implement the saadc_callback function, which will be called when SAADC interrupt is triggered
    APP_ERROR_CHECK(err_code);
		
    //Configure SAADC channel
    channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;                              //Set internal reference of fixed 0.6 volts
    channel_config.gain = NRF_SAADC_GAIN1_6;                                              //Set input gain to 1/6. The maximum SAADC input voltage is then 0.6V/(1/6)=3.6V. The single ended input range is then 0V-3.6V
    channel_config.acq_time = NRF_SAADC_ACQTIME_10US;                                     //Set acquisition time. Set low acquisition time to enable maximum sampling frequency of 200kHz. Set high acquisition time to allow maximum source resistance up to 800 kohm, see the SAADC electrical specification in the PS. 
    channel_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;                                    //Set SAADC as single ended. This means it will only have the positive pin as input, and the negative pin is shorted to ground (0V) internally.
    channel_config.pin_p = NRF_SAADC_INPUT_AIN0;                                          //Select the input pin for the channel. AIN0 pin maps to physical pin P0.02.
    channel_config.pin_n = NRF_SAADC_INPUT_DISABLED;                                      //Since the SAADC is single ended, the negative pin is disabled. The negative pin is shorted to ground internally.
    channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pullup resistor on the input pin
    channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pulldown resistor on the input pin

	
    //Initialize SAADC channel
    err_code = nrf_drv_saadc_channel_init(0, &channel_config);                            //Initialize SAADC channel 0 with the channel configuration
    APP_ERROR_CHECK(err_code);
		
    if(SAADC_BURST_MODE)
    {
        NRF_SAADC->CH[0].CONFIG |= 0x01000000;                                            //Configure burst mode for channel 0. Burst is useful together with oversampling. When triggering the SAMPLE task in burst mode, the SAADC will sample "Oversample" number of times as fast as it can and then output a single averaged value to the RAM buffer. If burst mode is not enabled, the SAMPLE task needs to be triggered "Oversample" number of times to output a single averaged value to the RAM buffer.		
    }

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);    //Set SAADC buffer 1. The SAADC will start to write to this buffer
    APP_ERROR_CHECK(err_code);

    
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);    //Set SAADC buffer 2. The SAADC will write to this buffer when buffer 1 is full. This will give the applicaiton time to process data in buffer 1.
    APP_ERROR_CHECK(err_code);

}
Example #2
0
File: main.c Project: JulianYG/WNR
/**@brief Function for configuring ADC to do battery level conversion.
 */
static void adc_configure(void)
{    
    #ifdef NRF51
    nrf_adc_config_t adc_config = NRF_ADC_CONFIG_DEFAULT;
    adc_config.scaling = NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD;
    nrf_adc_configure(&adc_config); 
    nrf_adc_int_enable(ADC_INTENSET_END_Msk);
    NVIC_EnableIRQ(ADC_IRQn);
    NVIC_SetPriority(ADC_IRQn, 3);
    nrf_adc_input_select(NRF_ADC_CONFIG_INPUT_DISABLED);
    #else //  NRF52
    ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
    err_code = nrf_drv_saadc_channel_init(0,&config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf[0],1);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(&adc_buf[1],1);
    APP_ERROR_CHECK(err_code);
    #endif //NRF51
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    ret_code_t err_code;
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)                                                        //Capture offset calibration complete event
    {
			
        LEDS_INVERT(BSP_LED_1_MASK);                                                                    //Toggle LED2 to indicate SAADC buffer full		

        if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0)                                  //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
        {
            nrf_drv_saadc_abort();                                                                      // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy
            m_saadc_calibrate = true;                                                                   // Set flag to trigger calibration in main context when SAADC is stopped
        }
        

#ifdef UART_PRINTING_ENABLED
        NRF_LOG_INFO("ADC event number: %d\r\n",(int)m_adc_evt_counter);                                //Print the event number on UART

        for (int i = 0; i < p_event->data.done.size; i++)
        {
            NRF_LOG_INFO("%d\r\n", p_event->data.done.p_buffer[i]);                                     //Print the SAADC result on UART
        }
#endif //UART_PRINTING_ENABLED      
        
        if(m_saadc_calibrate == false)
        {
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);             //Set buffer so the SAADC can write to it again. 
            APP_ERROR_CHECK(err_code);
        }
        
        m_adc_evt_counter++;
  
    }
    else if (p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
        LEDS_INVERT(BSP_LED_2_MASK);                                                                    //Toggle LED3 to indicate SAADC calibration complete
        
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAADC_SAMPLES_IN_BUFFER);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAADC_SAMPLES_IN_BUFFER);             //Need to setup both buffers, as they were both removed with the call to nrf_drv_saadc_abort before calibration.
        APP_ERROR_CHECK(err_code);
        
#ifdef UART_PRINTING_ENABLED
        NRF_LOG_INFO("SAADC calibration complete ! \r\n");                                              //Print on UART
#endif //UART_PRINTING_ENABLED	
        
    }
}
Example #4
0
File: main.c Project: JulianYG/WNR
/**@brief Function for handling the ADC interrupt.
 *
 * @details  This function will fetch the conversion result from the ADC, convert the value into
 *           percentage and send it to peer.
 */
void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t  adc_result;
        uint16_t batt_lvl_in_milli_volts;
        uint8_t  percentage_batt_lvl;
        uint32_t err_code;

        adc_result = p_event->data.done.p_buffer[0];

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,1);
        APP_ERROR_CHECK(err_code);

        batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) +
                                  DIODE_FWD_VOLT_DROP_MILLIVOLTS;
        percentage_batt_lvl     = battery_level_in_percent(batt_lvl_in_milli_volts);

        err_code = ble_bas_battery_level_update(&m_bas, percentage_batt_lvl);
        if (
            (err_code != NRF_SUCCESS)
            &&
            (err_code != NRF_ERROR_INVALID_STATE)
            &&
            (err_code != BLE_ERROR_NO_TX_PACKETS)
            &&
            (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
           )
        {
            APP_ERROR_HANDLER(err_code);
        }
    }
}
Example #5
0
/**
 * @brief Function for initializing SAADC.
 */
static ret_code_t saadc_init(void)
{
    ret_code_t err_code;
    static nrf_saadc_value_t saadc_value;

    saadc_channel.gain = NRF_SAADC_GAIN1_3;

   err_code = nrf_drv_saadc_init(NULL, saadc_handler);
   if (err_code != NRF_SUCCESS)
   {
       return NRF_ERROR_INTERNAL;
   }

    nrf_gpio_pin_set(m_csense.output_pin);

    err_code = nrf_drv_saadc_channel_init(0, &saadc_channel);
    if (err_code != NRF_SUCCESS)
    {
        return NRF_ERROR_INTERNAL;
    }

    err_code = nrf_drv_saadc_buffer_convert(&saadc_value, 1);
    if (err_code != NRF_SUCCESS)
    {
        return NRF_ERROR_INTERNAL;
    }

    nrf_saadc_disable();

    return NRF_SUCCESS;
}
Example #6
0
/**
 * @brief SAADC handler.
 *
 * @param[in] p_event                Pointer to analog-to-digital converter driver event.
 */
void saadc_handler(nrf_drv_saadc_evt_t const * p_event)
{
    nrf_gpio_pin_set(m_csense.output_pin);
    uint16_t val;
    (void)nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
    val = (uint16_t)(*p_event->data.done.p_buffer *
                      SAADC_REF_VBG_VOLTAGE * 1000 *
                      SAADC_INPUT_PRESCALER / SAADC_RES_10BIT);
    conversion_handler(val);
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;
        uint16_t adc_value;
        uint8_t value[SAADC_SAMPLES_IN_BUFFER*2];
        uint8_t bytes_to_send;
     
        // set buffers
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
						
        // print samples on hardware UART and parse data for BLE transmission
        printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);
        for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
        {
            printf("%d\r\n", p_event->data.done.p_buffer[i]);

            adc_value = p_event->data.done.p_buffer[i];
            value[i*2] = adc_value;
            value[(i*2)+1] = adc_value >> 8;
        }
				
        // Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
        if((SAADC_SAMPLES_IN_BUFFER*2) <= 20) 
        {
            bytes_to_send = (SAADC_SAMPLES_IN_BUFFER*2);
        }
        else 
        {
            bytes_to_send = 20;
        }
        err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
        if (err_code != NRF_ERROR_INVALID_STATE) 
        {
            APP_ERROR_CHECK(err_code);
        }
						
        m_adc_evt_counter++;
    }
Example #8
0
void SAADC_IRQHandler(void)
{
    if (nrf_saadc_event_check(NRF_SAADC_EVENT_END))
    {
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        if (m_cb.active_channels == 1)
        {
            nrf_drv_saadc_evt_t evt;
            evt.type = NRF_DRV_SAADC_EVT_DONE;
            evt.data.done.p_buffer = (nrf_saadc_value_t *)m_cb.buffer;
            evt.data.done.size = m_cb.buffer_size;

            if (m_cb.p_secondary_buffer == NULL)
            {
                m_cb.adc_state = NRF_SAADC_STATE_IDLE;
            }
            else
            {
                m_cb.buffer = m_cb.p_secondary_buffer;
                m_cb.buffer_size = m_cb.secondary_buffer_size;
                m_cb.p_secondary_buffer = NULL;
                nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
            }

            m_cb.event_handler(&evt);
        }
        else
        {
            //PAN-28: scan mode is not working correctly, emulated by interrupts
            m_cb.buffer_pos++;
            uint16_t buffer_pos = m_cb.buffer_pos;
            if (buffer_pos == m_cb.buffer_size)
            {
                nrf_drv_saadc_evt_t evt;
                evt.type = NRF_DRV_SAADC_EVT_DONE;
                evt.data.done.p_buffer = (nrf_saadc_value_t *)m_cb.buffer;
                evt.data.done.size = m_cb.buffer_size;

                m_cb.adc_state = NRF_SAADC_STATE_IDLE;
                if (m_cb.p_secondary_buffer == NULL)
                {
                    m_cb.adc_state = NRF_SAADC_STATE_IDLE;
                }
                else
                {
                    (void)nrf_drv_saadc_buffer_convert((nrf_saadc_value_t *)m_cb.p_secondary_buffer, (uint16_t)m_cb.secondary_buffer_size);
                }
                m_cb.event_handler(&evt);
            }
            else
            {
                //
                uint8_t current_scan_pos = m_cb.scan_pos;

                nrf_saadc_channel_input_set(current_scan_pos,
                                            NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);

                nrf_saadc_buffer_init((nrf_saadc_value_t *)(m_cb.buffer + m_cb.buffer_pos), 1);
                // Find the next enabled channel.
                for (++m_cb.scan_pos; m_cb.scan_pos < NRF_SAADC_CHANNEL_COUNT; ++m_cb.scan_pos)
                {
                    if (m_cb.psel[m_cb.scan_pos].pselp)
                    {
                        nrf_saadc_channel_input_set(m_cb.scan_pos,
                                    m_cb.psel[m_cb.scan_pos].pselp, m_cb.psel[m_cb.scan_pos].pseln);
                        nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
                        nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
                        return;
                    }
                }
                //if scanning is done prepare for next round.
                for (uint8_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i)
                {
                    if (m_cb.psel[i].pselp)
                    {
                        m_cb.scan_pos = i;
                        break;
                    }
                }
                nrf_saadc_channel_input_set(m_cb.scan_pos,
                                    m_cb.psel[m_cb.scan_pos].pselp, m_cb.psel[m_cb.scan_pos].pseln);
                nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
            }
        }
    }
    if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED))
    {
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
        m_cb.adc_state = NRF_SAADC_STATE_IDLE;
    }
    else
    {
        uint32_t limit_flags = m_cb.limits_enabled_flags;
        uint32_t flag_idx;
        nrf_saadc_event_t event;
        while (limit_flags)
        {
            flag_idx = __CLZ(limit_flags);
            limit_flags &= ~(0x80000000 >> flag_idx);
            event = FLAG_IDX_TO_EVENT(flag_idx);
            if (nrf_saadc_event_check(event))
            {
                nrf_saadc_event_clear(event);
                nrf_drv_saadc_evt_t evt;
                evt.type = NRF_DRV_SAADC_EVT_LIMIT;
                evt.data.limit.channel = LIMIT_EVENT_TO_CHANNEL(event);
                evt.data.limit.limit_type = LIMIT_EVENT_TO_LIMIT_TYPE(event);
                m_cb.event_handler(&evt);
            }
        }
    }
}