new upgrade
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
// components/evse/evse_pilot.c
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
@@ -13,153 +12,232 @@
|
||||
#include "adc121s021_dma.h"
|
||||
#include "board_config.h"
|
||||
|
||||
#define PILOT_PWM_TIMER LEDC_TIMER_0
|
||||
#define PILOT_PWM_CHANNEL LEDC_CHANNEL_0
|
||||
#define PILOT_PWM_SPEED_MODE LEDC_LOW_SPEED_MODE
|
||||
#define PILOT_PWM_DUTY_RES LEDC_TIMER_10_BIT
|
||||
#define PILOT_PWM_MAX_DUTY 1023
|
||||
#define PILOT_PWM_TIMER LEDC_TIMER_0
|
||||
#define PILOT_PWM_CHANNEL LEDC_CHANNEL_0
|
||||
#define PILOT_PWM_SPEED_MODE LEDC_LOW_SPEED_MODE
|
||||
#define PILOT_PWM_DUTY_RES LEDC_TIMER_10_BIT
|
||||
#define PILOT_PWM_MAX_DUTY 1023
|
||||
|
||||
#define NUM_PILOT_SAMPLES 100
|
||||
#define MAX_SAMPLE_ATTEMPTS 1000
|
||||
#define PILOT_EXTREME_PERCENT 10 // 10% superior e inferior
|
||||
// --- Configuração de amostragem do Pilot ---
|
||||
#define NUM_PILOT_SAMPLES 100
|
||||
#define MAX_SAMPLE_ATTEMPTS 1000
|
||||
|
||||
#define ADC121_VREF_MV 3300
|
||||
#define ADC121_MAX 4095
|
||||
#define PILOT_SAMPLE_DELAY_US 10
|
||||
|
||||
// Percentagem para descartar extremos superior/inferior (ruído)
|
||||
#define PILOT_EXTREME_PERCENT 10 // 10% superior e inferior
|
||||
|
||||
// ADC referência
|
||||
#define ADC121_VREF_MV 3300
|
||||
#define ADC121_MAX 4095
|
||||
|
||||
static const char *TAG = "evse_pilot";
|
||||
|
||||
static int last_pilot_level = -1;
|
||||
static uint32_t last_pwm_duty = 0;
|
||||
typedef enum {
|
||||
PILOT_MODE_DC_HIGH = 0, // +12V (nível alto)
|
||||
PILOT_MODE_DC_LOW, // nível baixo / pilot desligado (dependente do hardware)
|
||||
PILOT_MODE_PWM // PWM ativo
|
||||
} pilot_mode_t;
|
||||
|
||||
static int adc_raw_to_mv(uint16_t raw) {
|
||||
return (raw * ADC121_VREF_MV) / ADC121_MAX;
|
||||
static pilot_mode_t s_mode = PILOT_MODE_DC_LOW;
|
||||
static uint32_t last_pwm_duty = 0;
|
||||
|
||||
// ---------------------
|
||||
// Helpers internos
|
||||
// ---------------------
|
||||
static int adc_raw_to_mv(uint16_t raw)
|
||||
{
|
||||
return (int)((raw * ADC121_VREF_MV) / ADC121_MAX);
|
||||
}
|
||||
|
||||
static int compare_uint16(const void *a, const void *b)
|
||||
{
|
||||
uint16_t va = *(const uint16_t *)a;
|
||||
uint16_t vb = *(const uint16_t *)b;
|
||||
if (va < vb) return -1;
|
||||
if (va > vb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// Inicialização PWM + ADC
|
||||
// ---------------------
|
||||
void pilot_init(void)
|
||||
{
|
||||
// Configura timer do PWM do Pilot (1 kHz)
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = PILOT_PWM_SPEED_MODE,
|
||||
.timer_num = PILOT_PWM_TIMER,
|
||||
.duty_resolution = PILOT_PWM_DUTY_RES,
|
||||
.freq_hz = 1000,
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
.speed_mode = PILOT_PWM_SPEED_MODE,
|
||||
.timer_num = PILOT_PWM_TIMER,
|
||||
.duty_resolution = PILOT_PWM_DUTY_RES,
|
||||
.freq_hz = 1000, // 1 kHz (IEC 61851)
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
|
||||
// Canal do PWM no pino configurado em board_config
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.speed_mode = PILOT_PWM_SPEED_MODE,
|
||||
.channel = PILOT_PWM_CHANNEL,
|
||||
.timer_sel = PILOT_PWM_TIMER,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = board_config.pilot_pwm_gpio,
|
||||
.duty = 0,
|
||||
.hpoint = 0
|
||||
.channel = PILOT_PWM_CHANNEL,
|
||||
.timer_sel = PILOT_PWM_TIMER,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = board_config.pilot_pwm_gpio,
|
||||
.duty = 0,
|
||||
.hpoint = 0
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, 0));
|
||||
|
||||
// Garante que começa parado e em idle baixo (pilot off)
|
||||
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, 0));
|
||||
s_mode = PILOT_MODE_DC_LOW;
|
||||
last_pwm_duty = 0;
|
||||
|
||||
// Inicializa driver do ADC121S021
|
||||
adc121s021_dma_init();
|
||||
}
|
||||
|
||||
void pilot_set_level(bool level)
|
||||
// ---------------------
|
||||
// Controlo do modo do Pilot
|
||||
// ---------------------
|
||||
void pilot_set_level(bool high)
|
||||
{
|
||||
if (last_pilot_level == level) return;
|
||||
last_pilot_level = level;
|
||||
pilot_mode_t target = high ? PILOT_MODE_DC_HIGH : PILOT_MODE_DC_LOW;
|
||||
|
||||
ESP_LOGI(TAG, "Set level %d", level);
|
||||
ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, level ? 1 : 0);
|
||||
// Se já estiver no modo DC desejado e sem PWM ativo, ignora
|
||||
if (s_mode == target && last_pwm_duty == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Pilot set DC level: %s", high ? "HIGH(+12V)" : "LOW/OFF");
|
||||
|
||||
// Para PWM e fixa o nível idle do GPIO
|
||||
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, high ? 1 : 0));
|
||||
|
||||
s_mode = target;
|
||||
last_pwm_duty = 0;
|
||||
}
|
||||
|
||||
void pilot_set_amps(uint16_t amps)
|
||||
{
|
||||
if (amps < 6 || amps > 80) {
|
||||
if (amps < 6 || amps > 80)
|
||||
{
|
||||
ESP_LOGE(TAG, "Invalid ampere value: %d A (valid: 6–80 A)", amps);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t duty_percent;
|
||||
if (amps <= 51) {
|
||||
if (amps <= 51)
|
||||
{
|
||||
duty_percent = (amps * 10) / 6;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
duty_percent = (amps * 10) / 25 + 64;
|
||||
}
|
||||
if (duty_percent > 100) duty_percent = 100;
|
||||
|
||||
uint32_t duty = (PILOT_PWM_MAX_DUTY * duty_percent) / 100;
|
||||
|
||||
if (last_pilot_level == 0 && last_pwm_duty == duty) return;
|
||||
last_pilot_level = 0;
|
||||
// Se já estiver em PWM com o mesmo duty, ignora
|
||||
if (s_mode == PILOT_MODE_PWM && last_pwm_duty == duty) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_mode = PILOT_MODE_PWM;
|
||||
last_pwm_duty = duty;
|
||||
|
||||
ESP_LOGI(TAG, "Pilot set: %d A → %d/%d (≈ %d%% duty)",
|
||||
ESP_LOGI(TAG, "Pilot set PWM: %d A → %d/%d (≈ %d%% duty)",
|
||||
amps, (int)duty, PILOT_PWM_MAX_DUTY, (int)duty_percent);
|
||||
|
||||
ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty);
|
||||
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
|
||||
ESP_ERROR_CHECK(ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty));
|
||||
ESP_ERROR_CHECK(ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL));
|
||||
}
|
||||
|
||||
bool pilot_get_state(void) {
|
||||
return (last_pilot_level == 1) && (last_pwm_duty == 0);
|
||||
}
|
||||
|
||||
static int compare_int(const void *a, const void *b) {
|
||||
return (*(const int *)a - *(const int *)b);
|
||||
bool pilot_get_state(void)
|
||||
{
|
||||
// "Alto" significa DC +12V (estado A). PWM não conta como DC high.
|
||||
return (s_mode == PILOT_MODE_DC_HIGH);
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// Medição do sinal de Pilot (PWM 1 kHz J1772)
|
||||
// ---------------------
|
||||
void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
|
||||
{
|
||||
ESP_LOGD(TAG, "pilot_measure");
|
||||
|
||||
int samples[NUM_PILOT_SAMPLES];
|
||||
int collected = 0, attempts = 0;
|
||||
uint16_t adc_sample = 0;
|
||||
uint16_t samples[NUM_PILOT_SAMPLES];
|
||||
int collected = 0;
|
||||
int attempts = 0;
|
||||
|
||||
while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS) {
|
||||
adc_sample = 0;
|
||||
if (adc121s021_dma_get_sample(&adc_sample)) {
|
||||
while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS)
|
||||
{
|
||||
uint16_t adc_sample;
|
||||
|
||||
if (adc121s021_dma_get_sample(&adc_sample))
|
||||
{
|
||||
samples[collected++] = adc_sample;
|
||||
esp_rom_delay_us(10);
|
||||
} else {
|
||||
esp_rom_delay_us(PILOT_SAMPLE_DELAY_US);
|
||||
}
|
||||
else
|
||||
{
|
||||
esp_rom_delay_us(100);
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (collected < NUM_PILOT_SAMPLES) {
|
||||
if (collected < NUM_PILOT_SAMPLES)
|
||||
{
|
||||
ESP_LOGW(TAG, "Timeout on sample read (%d/%d)", collected, NUM_PILOT_SAMPLES);
|
||||
*up_voltage = PILOT_VOLTAGE_1;
|
||||
*down_voltage_n12 = false;
|
||||
return;
|
||||
}
|
||||
|
||||
qsort(samples, collected, sizeof(int), compare_int);
|
||||
// Ordena as amostras para eliminar extremos (ruído/espúrios)
|
||||
qsort(samples, collected, sizeof(uint16_t), compare_uint16);
|
||||
|
||||
int k = (collected * PILOT_EXTREME_PERCENT) / 100;
|
||||
if (k == 0) k = 1;
|
||||
if (k < 2) k = 2; // garante margem mínima
|
||||
|
||||
// descarta k/2 em cada lado (aprox. 10% total, mantendo simetria)
|
||||
int low_index = k / 2;
|
||||
int high_index = collected - k + (k / 2);
|
||||
if (high_index >= collected) high_index = collected - 1;
|
||||
int high_index = collected - 1 - (k / 2);
|
||||
|
||||
int low_raw = samples[low_index];
|
||||
int high_raw = samples[high_index];
|
||||
if (low_index < 0) low_index = 0;
|
||||
if (high_index >= collected) high_index = collected - 1;
|
||||
if (high_index <= low_index) high_index = low_index;
|
||||
|
||||
uint16_t low_raw = samples[low_index];
|
||||
uint16_t high_raw = samples[high_index];
|
||||
|
||||
int high_mv = adc_raw_to_mv(high_raw);
|
||||
int low_mv = adc_raw_to_mv(low_raw);
|
||||
|
||||
// Determina o nível positivo (+12, +9, +6, +3 ou <3 V)
|
||||
if (high_mv >= board_config.pilot_down_threshold_12)
|
||||
{
|
||||
*up_voltage = PILOT_VOLTAGE_12;
|
||||
}
|
||||
else if (high_mv >= board_config.pilot_down_threshold_9)
|
||||
{
|
||||
*up_voltage = PILOT_VOLTAGE_9;
|
||||
}
|
||||
else if (high_mv >= board_config.pilot_down_threshold_6)
|
||||
{
|
||||
*up_voltage = PILOT_VOLTAGE_6;
|
||||
}
|
||||
else if (high_mv >= board_config.pilot_down_threshold_3)
|
||||
{
|
||||
*up_voltage = PILOT_VOLTAGE_3;
|
||||
}
|
||||
else
|
||||
{
|
||||
*up_voltage = PILOT_VOLTAGE_1;
|
||||
}
|
||||
|
||||
// Verifica se o nível negativo atinge -12 V (diodo presente, C/D válidos)
|
||||
*down_voltage_n12 = (low_mv <= board_config.pilot_down_threshold_n12);
|
||||
|
||||
ESP_LOGD(TAG, "Final: up_voltage=%d, down_voltage_n12=%d", *up_voltage, *down_voltage_n12);
|
||||
ESP_LOGD(TAG, "Final: up_voltage=%d, down_voltage_n12=%d (high=%d mV, low=%d mV)",
|
||||
*up_voltage, *down_voltage_n12, high_mv, low_mv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user