/******************************************************************************* * @file battery_saadc.c * @author CandyPops Co. * @version V1.0.0 * @date 2022-09-05 * @brief ******************************************************************************/ #include "sdk_common.h" #include #include #include "nrf.h" #include "boards.h" #include "app_error.h" #include "nrf_drv_saadc.h" #include "nrf_drv_timer.h" #include "ble_nus.h" #include "nrf_log.h" #include "main.h" #include "app_timer.h" //#include "fstorage.h" #include "battery_saadc.h" #include "main_timer.h" #include #include "debug_print.h" #define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */ #define BATTERY_PRE_SCALING_COMPENSATION 6 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/ #define BATTERY_ADC_RES_10BITS 1023 /**< Maximum digital value for 10-bit ADC conversion. */ //#define PRESSURE_RESULT_IN_MILLI_VOLTS(adc) ((adc * 3600) / 1023) #define PRESSURE_OFFSET_DEFAULT 0 // ?? offset. ?? ? ??? ?? ??. #define MV_PER_ADC_STEP 805 // ? 0.805mV per 1 LSB (nRF 12bit + scaling) /**@brief Macro to convert the result of ADC conversion in millivolts. * * @param[in] ADC_VALUE ADC result. * * @retval Result converted to millivolts. */ #define BATTERY_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\ ((((ADC_VALUE) * BATTERY_REF_VOLTAGE_IN_MILLIVOLTS) / BATTERY_ADC_RES_10BITS) * BATTERY_PRE_SCALING_COMPENSATION) static nrf_saadc_value_t adc_bufs[2]; static int16_t pressure_adc_buf[2]; //cj add 25/11/19 static uint16_t convert_adc_to_mV(int16_t raw_adc); //cj add 25/11/19 APP_TIMER_DEF(m_battery_loop_timer_id); #define BATTERY_LOOP_INTERVAL 5000 bool low_battery_check = false; extern bool info4; //cmd_parse // cj add edit 25/11/24 volatile uint16_t info_p1; volatile uint16_t info_p2; extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; extern bool go_device_power_off; extern volatile bool processing; extern which_cmd_t cmd_type_t; extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; volatile uint16_t info_batt; //48_c extern bool go_temp; // extern bool go_batt; //cmd_parse extern bool motion_raw_data_enabled ; extern bool ble_got_new_data; extern bool motion_data_once ; /**@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. */ static uint16_t convert_adc_to_mV(int16_t raw_adc) { if (raw_adc < 0) raw_adc = 0; int32_t mv = (int32_t)raw_adc * MV_PER_ADC_STEP; // ?: 805 uV mv /= 1000; // ===== (3) 0~3500mV ??? ???? ?? ?? ===== if (mv < 0) mv = 0; if (mv > 3500) mv = 3500; return (uint16_t)mv; } void pressure_all_event_handler(nrf_drv_saadc_evt_t const * p_event) { if (p_event->type == NRF_DRV_SAADC_EVT_DONE) { int16_t p1_adc = p_event->data.done.p_buffer[0]; // AIN7 int16_t p2_adc = p_event->data.done.p_buffer[1]; // AIN4 uint16_t p1_mV = convert_adc_to_mV(p1_adc); uint16_t p2_mV = convert_adc_to_mV(p2_adc); // PD Full mode(info4=true)When info_p1/info_p2 to Update if(info4 == true) { info_p1 = p1_mV; info_p2 = p2_mV; } // Re-buffer APP_ERROR_CHECK(nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 2)); // uninit nrf_drv_saadc_uninit(); nrf_drv_saadc_channel_uninit(0); nrf_drv_saadc_channel_uninit(1); // UART send if(cmd_type_t == CMD_UART) { DBG_PRINTF("P1:%d P2:%d\r\n", p1_mV, p2_mV); } else if(cmd_type_t == CMD_BLE && info4 == false) { DBG_PRINTF("P1:%d P2:%d\r\n", p1_mV, p2_mV); // uint16_t len = sprintf((char*)ble_bin_buffer, // "rpn:%04x,%04x", p1_mV, p2_mV); uint16_t result_data[2]; result_data[0] = p1_mV; result_data[1] = p2_mV; format_data(ble_bin_buffer, "rpn:", result_data,2); dr_binary_tx_safe(ble_bin_buffer,4); } } } void battery_event_handler( nrf_drv_saadc_evt_t const * p_event ) { static uint8_t low_battery_cnt = 0; if (p_event->type == NRF_DRV_SAADC_EVT_DONE) { nrf_saadc_value_t register_val = 0; uint16_t batt_lvl_in_milli_volt_0 = 0; uint16_t batt_lvl_in_milli_volt_1 = 0; uint32_t err_code = 0; register_val = 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); nrf_drv_saadc_uninit(); nrf_drv_saadc_channel_uninit(0); batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val); batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42; if(low_battery_check == true) { low_battery_check = false; if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE) { if(low_battery_cnt >= 10) { low_battery_cnt = 0; /*go to power off and fds save */ DBG_PRINTF("Save FDS parameters and then Power OFF\r\n"); go_device_power_off = true; main_timer_start(); }else{ low_battery_cnt++; DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, batt_lvl_in_milli_volt_1); } } } else if (info4 == true){ info_batt = batt_lvl_in_milli_volt_1; DBG_PRINTF("INFOTn%d\r\n\r\n", batt_lvl_in_milli_volt_1); } else { if(cmd_type_t == CMD_UART) { DBG_PRINTF("Tn%d\r\n\r\n", batt_lvl_in_milli_volt_1); } else if(cmd_type_t == CMD_BLE) { single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1); dr_binary_tx_safe(ble_bin_buffer,3); //data_tx_handler(ble_tx_buffer); } } } if (info4 == true){ go_batt =false; go_temp = true; main_timer_start(); } } /**@brief Function for configuring ADC to do battery level conversion. */ static void battery_configure(void) { ret_code_t err_code = nrf_drv_saadc_init(NULL, battery_event_handler); APP_ERROR_CHECK(err_code); nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); err_code = nrf_drv_saadc_channel_init(0, &config); APP_ERROR_CHECK(err_code); err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[0], 1); APP_ERROR_CHECK(err_code); err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[1], 1); APP_ERROR_CHECK(err_code); } void pressure_all_configure(void) { ret_code_t err_code; err_code = nrf_drv_saadc_init(NULL, pressure_all_event_handler); if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { DBG_PRINTF("SAADC init err=%d\r\n", err_code); return; } nrf_saadc_channel_config_t ch0_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); nrf_saadc_channel_config_t ch1_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); err_code = nrf_drv_saadc_channel_init(0, &ch0_cfg); if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { DBG_PRINTF("SAADC ch0 init err=%d\r\n", err_code); return; } err_code = nrf_drv_saadc_channel_init(1, &ch1_cfg); if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) { DBG_PRINTF("SAADC ch1 init err=%d\r\n", err_code); return; } err_code = nrf_drv_saadc_buffer_convert(pressure_adc_buf, 2); if (err_code != NRF_SUCCESS) { DBG_PRINTF("SAADC buf conv err=%d\r\n", err_code); return; } } void battery_level_meas(void) { ret_code_t err_code; battery_configure(); err_code = nrf_drv_saadc_sample(); APP_ERROR_CHECK(err_code); } void pressure_all_level_meas(void) //add cj add 25/11/19 { ret_code_t err_code; pressure_all_configure(); // 2 err_code = nrf_drv_saadc_sample(); APP_ERROR_CHECK(err_code); } void battery_loop(void * p_context) /* For 1sec */ { UNUSED_PARAMETER(p_context); if(processing==true) { processing = false ; // add 20241218 //low_battery_check = true; return;} else{ low_battery_check = true; battery_level_meas(); } } void battery_timer_start(void) { APP_ERROR_CHECK(app_timer_start(m_battery_loop_timer_id, APP_TIMER_TICKS(BATTERY_LOOP_INTERVAL), NULL)); } void battery_timer_stop(void) { APP_ERROR_CHECK(app_timer_stop(m_battery_loop_timer_id)); } void battery_timer_init(void) { APP_ERROR_CHECK(app_timer_create(&m_battery_loop_timer_id, APP_TIMER_MODE_REPEATED, battery_loop)); }