215 lines
5.1 KiB
C
215 lines
5.1 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "configuration.h"
|
|
#include "driver/adc_types_legacy.h"
|
|
#include "driver/gpio.h"
|
|
#include "esp_adc/adc_cali.h"
|
|
#include "esp_adc/adc_continuous.h"
|
|
#include "esp_adc/adc_oneshot.h"
|
|
#include "esp_intr_alloc.h"
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/portmacro.h"
|
|
#include "hal/adc_types.h"
|
|
#include "hal/gpio_types.h"
|
|
#include "nvs_flash.h"
|
|
|
|
#include "power_profiler.h"
|
|
#include "resistor_ranges.h"
|
|
#include "measure.h"
|
|
#include "ble.h"
|
|
|
|
#define TAG "main"
|
|
|
|
// mV value that we consider the threshold for activating the next higher resistance
|
|
#define UNDERRANGE_MV 10
|
|
// source for the comparison used for the range switching
|
|
#define UNDERRANGE_SRC X10
|
|
// number of consecutive times the input has to be below the threshold before switching
|
|
#define UNDERRANGE_NUM 3
|
|
|
|
resistor_range ranges[] = {
|
|
[R1] = {
|
|
.pin = GPIO_NUM_6,
|
|
.resistance = 1000,
|
|
},
|
|
[R10] = {
|
|
.pin = GPIO_NUM_7,
|
|
.resistance = 10000,
|
|
},
|
|
[R100] = {
|
|
.pin = GPIO_NUM_NC,
|
|
.resistance = 100000,
|
|
},
|
|
};
|
|
|
|
measurement_input inputs[] = {
|
|
[X1] = {
|
|
.channel = ADC1_CHANNEL_3,
|
|
.gain = 1,
|
|
},
|
|
[X10] = {
|
|
.channel = ADC1_CHANNEL_0,
|
|
.gain = 10,
|
|
},
|
|
[X100] = {
|
|
.channel = ADC1_CHANNEL_1,
|
|
.gain = 100,
|
|
},
|
|
};
|
|
|
|
static spinlock_t adc_res_mutex;
|
|
volatile uint32_t meas_res[INPUTS_NUM];
|
|
volatile uint32_t meas_nb[INPUTS_NUM];
|
|
|
|
int get_input_index_from_channel(adc_channel_t channel){
|
|
switch(channel){
|
|
case ADC1_CHANNEL_3:
|
|
return 0;
|
|
case ADC1_CHANNEL_0:
|
|
return 1;
|
|
case ADC1_CHANNEL_1:
|
|
return 2;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static bool IRAM_ATTR on_conv_done(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data){
|
|
adc_digi_output_data_t* res = (adc_digi_output_data_t*)edata->conv_frame_buffer;
|
|
|
|
int index = get_input_index_from_channel(res->type2.channel);
|
|
meas_res[index] += res->type2.data;
|
|
meas_nb[index]++;
|
|
|
|
return false;
|
|
}
|
|
|
|
configuration main_conf = {
|
|
.refresh_delay = 1000,
|
|
.range = R100,
|
|
.zero_cali_nsamp = 10000,
|
|
.auto_range = 1,
|
|
.ranges = ranges,
|
|
.ranges_num = R_NUM,
|
|
};
|
|
|
|
uint8_t notify_range_f = 0;
|
|
|
|
static void IRAM_ATTR overrange_handler(void* arg)
|
|
{
|
|
if(!main_conf.auto_range) return;
|
|
|
|
activate_range(ranges, 0, R_NUM - 1);
|
|
main_conf.range = 0;
|
|
notify_range_f = 1;
|
|
}
|
|
|
|
void app_main(void){
|
|
gpio_config_t overrange_input = {
|
|
.intr_type = GPIO_INTR_POSEDGE,
|
|
.mode = GPIO_MODE_INPUT,
|
|
.pin_bit_mask = 1ULL << OVERRANGE_PIN,
|
|
.pull_down_en = 0,
|
|
.pull_up_en = 0,
|
|
};
|
|
gpio_config(&overrange_input);
|
|
|
|
gpio_install_isr_service(0);
|
|
|
|
gpio_isr_handler_add(OVERRANGE_PIN, overrange_handler, NULL);
|
|
|
|
set_resistor_gpio(ranges, R100);
|
|
|
|
activate_range(ranges, R100, R100);
|
|
|
|
adc_continuous_handle_t adc_handle = init_measurement_inputs(inputs, INPUTS_NUM);
|
|
|
|
spinlock_initialize(&adc_res_mutex);
|
|
adc_cali_handle_t adc_conv_h[INPUTS_NUM];
|
|
init_conv_driver(inputs, INPUTS_NUM, adc_conv_h);
|
|
|
|
adc_continuous_evt_cbs_t adc_event = {
|
|
.on_conv_done = &on_conv_done,
|
|
.on_pool_ovf = NULL,
|
|
};
|
|
ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_event, NULL));
|
|
ESP_ERROR_CHECK(adc_continuous_start(adc_handle));
|
|
|
|
ESP_ERROR_CHECK(nvs_flash_init());
|
|
|
|
uint32_t offsets[INPUTS_NUM] = {0};
|
|
|
|
main_conf.offsets = offsets;
|
|
|
|
init_configuration_from_nvs(&main_conf);
|
|
|
|
uint32_t meas_volts[INPUTS_NUM];
|
|
uint32_t meas_amp[INPUTS_NUM];
|
|
measurements meas = {
|
|
.raw_volt = meas_volts,
|
|
.amperes = meas_amp,
|
|
};
|
|
|
|
measurements_ctxt meas_ctxt = {
|
|
.handle = adc_handle,
|
|
.inputs = inputs,
|
|
.nb_inputs = INPUTS_NUM,
|
|
};
|
|
|
|
initBLE(&main_conf, &meas, &meas_ctxt);
|
|
|
|
int underrange_counter = 0;
|
|
|
|
while(1){
|
|
uint32_t meas_res_buff[INPUTS_NUM];
|
|
uint32_t meas_nb_buff[INPUTS_NUM];
|
|
|
|
portENTER_CRITICAL(&adc_res_mutex);
|
|
for(int i = 0; i < INPUTS_NUM; i++){
|
|
meas_res_buff[i] = meas_res[i];
|
|
meas_res[i] = 0;
|
|
|
|
meas_nb_buff[i] = meas_nb[i];
|
|
meas_nb[i] = 0;
|
|
}
|
|
portEXIT_CRITICAL(&adc_res_mutex);
|
|
|
|
for(int i = 0; i < INPUTS_NUM; i++){
|
|
int mv;
|
|
uint32_t val = meas_res_buff[i]/meas_nb_buff[i];
|
|
val = (val >= offsets[i])?(val-offsets[i]):0;
|
|
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_conv_h[i], val, &mv));
|
|
ESP_LOGI(TAG, "IN %d : %d mV (%lu / %lu)", i, mv, meas_res_buff[i], meas_nb_buff[i]);
|
|
meas_volts[i] = mv;
|
|
meas_amp[i] = mv * 1000000L / ranges[main_conf.range].resistance / inputs[i].gain;
|
|
}
|
|
|
|
if(meas_volts[UNDERRANGE_SRC] < UNDERRANGE_MV){
|
|
underrange_counter++;
|
|
if(underrange_counter > UNDERRANGE_NUM && main_conf.auto_range){
|
|
if(main_conf.range < R_NUM - 1){
|
|
main_conf.range++;
|
|
activate_range(ranges, main_conf.range, R_NUM - 1);
|
|
notify_range_f = 1;
|
|
}
|
|
underrange_counter = 0;
|
|
}
|
|
}
|
|
else{
|
|
underrange_counter = 0;
|
|
}
|
|
|
|
notify_update(&meas);
|
|
if(notify_range_f){
|
|
notify_range_f = 0;
|
|
notify_range(&main_conf);
|
|
}
|
|
|
|
vTaskDelay(main_conf.refresh_delay / portTICK_PERIOD_MS);
|
|
}
|
|
}
|