Finalize unified firmware!

This commit is contained in:
Ashcon Mohseninia 2022-11-30 20:19:58 +00:00
parent fa7e36417a
commit d84e77d799
21 changed files with 365 additions and 1714 deletions

View File

@ -152,7 +152,7 @@ def get_project_name(env) -> Tuple[str, str]:
return progname.fallback_get(
(
lambda: "{}_{}".format(env.GetProjectOption("egs_ver"), branch), #env.GetProjectOption(progname.PROG_NAME_OPTION, None),
lambda: "unified-un52",
"custom_option",
),
(lambda: git_relative_dir(), "git_relative_dir"),

View File

@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = prod-pcb
default_envs = unified
[env]
platform = espressif32@5.0.0
@ -24,13 +24,8 @@ monitor_port = /dev/ttyUSB0
board_build.partitions = partitions.csv
extra_scripts = post:patchappinfo.py
[env:prod-pcb]
build_flags = -Wall -DEGS51_MODE
egs_ver = egs51
[env:red-pcb]
build_flags = -Wall -DEGS52_MODE -DRED_BCB
egs_ver = egs52
[env:unified]
build_flags = -Wall
[env:latest_stable]
platform = linux_x86_64

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#include "pins.h"
#include "board_config.h"
#include "esp_log.h"
BoardGpioMatrix::BoardGpioMatrix(){}
@ -28,6 +28,19 @@ BoardV11GpioMatrix::BoardV11GpioMatrix() : BoardGpioMatrix() {
this->spc_pwm = gpio_num_t::GPIO_NUM_12; // Shift pressure solenoid (PWM output)
this->tcc_sense = gpio_num_t::GPIO_NUM_33; // Torque converter solenoid(Current feedback)
this->tcc_pwm = gpio_num_t::GPIO_NUM_13; // Torque converter solenoid (PWM output)
#define ADC_CHANNEL_VBATT_V12 adc2_channel_t::ADC2_CHANNEL_8
#define ADC_CHANNEL_ATF_V12 adc2_channel_t::ADC2_CHANNEL_7
this->sensor_data = SensorFuncData {
.batt_channel = adc2_channel_t::ADC2_CHANNEL_8,
.atf_channel = adc2_channel_t::ADC2_CHANNEL_9,
.adc_batt = adc_channel_t::ADC_CHANNEL_8,
.adc_atf = adc_channel_t::ADC_CHANNEL_9,
.atf_calibration_curve = atf_temp_lookup_V11,
.current_sense_multi = 2.0,
};
}
BoardV12GpioMatrix::BoardV12GpioMatrix() : BoardGpioMatrix() {
@ -55,6 +68,14 @@ BoardV12GpioMatrix::BoardV12GpioMatrix() : BoardGpioMatrix() {
this->tcc_pwm = gpio_num_t::GPIO_NUM_13; // Torque converter solenoid (PWM output)
this->i2c_sda = gpio_num_t::GPIO_NUM_15; // I2C clock
this->i2c_scl = gpio_num_t::GPIO_NUM_2; // I2C data
this->sensor_data = SensorFuncData {
.batt_channel = adc2_channel_t::ADC2_CHANNEL_8,
.atf_channel = adc2_channel_t::ADC2_CHANNEL_7,
.adc_batt = adc_channel_t::ADC_CHANNEL_8,
.adc_atf = adc_channel_t::ADC_CHANNEL_7,
.atf_calibration_curve = atf_temp_lookup_V12,
.current_sense_multi = 1.0,
};
}
BoardV13GpioMatrix::BoardV13GpioMatrix() : BoardGpioMatrix() {
@ -81,6 +102,14 @@ BoardV13GpioMatrix::BoardV13GpioMatrix() : BoardGpioMatrix() {
this->tcc_pwm = gpio_num_t::GPIO_NUM_13; // Torque converter solenoid (PWM output)
this->i2c_sda = gpio_num_t::GPIO_NUM_15; // I2C clock
this->i2c_scl = gpio_num_t::GPIO_NUM_2; // I2C data
this->sensor_data = SensorFuncData {
.batt_channel = adc2_channel_t::ADC2_CHANNEL_8,
.atf_channel = adc2_channel_t::ADC2_CHANNEL_7,
.adc_batt = adc_channel_t::ADC_CHANNEL_8,
.adc_atf = adc_channel_t::ADC_CHANNEL_7,
.atf_calibration_curve = atf_temp_lookup_V12,
.current_sense_multi = 1.0,
};
}
BoardGpioMatrix* pcb_gpio_matrix = nullptr;

152
src/board_config.h Normal file
View File

@ -0,0 +1,152 @@
#ifndef __PINS_H_
#define __PINS_H_
#include <driver/gpio.h>
#include <driver/adc.h>
#define NUM_TEMP_POINTS 22
typedef struct {
// Voltage in mV
uint16_t v;
// ATF Temp in degrees C * 10
int temp;
} temp_reading_t;
const static temp_reading_t atf_temp_lookup_V12[NUM_TEMP_POINTS] = {
// mV, Temp(x10)
// mV Values are calibrated on 3.45V rail
// as that is how much the ATF sensor power gets
{725, -400},
{784, -300},
{842, -200},
{900, -100},
{957, 0},
{1013, 100},
{1068, 200},
{1123, 300},
{1177, 400},
{1230, 500},
{1281, 600},
{1332, 700},
{1384, 800},
{1438, 900},
{1488, 1000},
{1538, 1100},
{1587, 1200},
{1636, 1300},
{1685, 1400},
{1732, 1500},
{1779, 1600},
{1826, 1700}
};
const static temp_reading_t atf_temp_lookup_V11[NUM_TEMP_POINTS] = {
// mV, Temp(x10)
// mV Values are calibrated on 3.45V rail
// as that is how much the ATF sensor power gets
{446, -400},
{461, -300},
{476, -200},
{491, -100},
{507, 0},
{523, 100},
{540, 200},
{557, 300},
{574, 400},
{592, 500},
{610, 600},
{629, 700},
{648, 800},
{669, 900},
{690, 1000},
{711, 1100},
{732, 1200},
{755, 1300},
{778, 1400},
{802, 1500},
{814, 1600},
{851, 1700}
};
typedef struct {
adc2_channel_t batt_channel;
adc2_channel_t atf_channel;
adc_channel_t adc_batt;
adc_channel_t adc_atf;
const temp_reading_t* atf_calibration_curve;
float current_sense_multi;
} SensorFuncData;
class BoardGpioMatrix {
public:
BoardGpioMatrix();
gpio_num_t can_tx_pin;
gpio_num_t can_rx_pin;
gpio_num_t spkr_pin;
gpio_num_t vsense_pin;
gpio_num_t atf_pin;
gpio_num_t n3_pin;
gpio_num_t n2_pin;
gpio_num_t io_pin; // Only on 1.3 and newer
gpio_num_t y3_sense;
gpio_num_t y3_pwm;
gpio_num_t y4_sense;
gpio_num_t y4_pwm;
gpio_num_t y5_sense;
gpio_num_t y5_pwm;
gpio_num_t mpc_sense;
gpio_num_t mpc_pwm;
gpio_num_t spc_sense;
gpio_num_t spc_pwm;
gpio_num_t tcc_sense;
gpio_num_t tcc_pwm;
gpio_num_t i2c_sda; // Only on 1.2 and newer
gpio_num_t i2c_scl; // Only on 1.2 and newer
SensorFuncData sensor_data;
};
/**
* @brief GPIO Matrix for the Red beta PCB (V1.1 12/12/21)
*
* NOTE: This will be removed from the code base once all beta boards have been replaced
*
*/
class BoardV11GpioMatrix: public BoardGpioMatrix {
public:
BoardV11GpioMatrix();
};
/**
* @brief GPIO Matrix for the Gen 1 production PCB (V1.2 07/07/22)
*
*/
class BoardV12GpioMatrix: public BoardGpioMatrix {
public:
BoardV12GpioMatrix();
};
/**
* @brief GPIO Matrix for the Gen 2 production PCB (V1.3 29/11/22)
* NOTE: This PCB is in development, so its matrix can change
*/
class BoardV13GpioMatrix: public BoardGpioMatrix {
public:
BoardV13GpioMatrix();
};
extern BoardGpioMatrix* pcb_gpio_matrix;
#endif

View File

@ -5,7 +5,7 @@
#include "driver/twai.h"
#include "gearbox_config.h"
#include "driver/i2c.h"
#include "pins.h"
#include "board_config.h"
Egs51Can::Egs51Can(const char* name, uint8_t tx_time_ms)
: AbstractCan(name, tx_time_ms)

View File

@ -1,7 +1,7 @@
#include "can_egs52.h"
#include "driver/twai.h"
#include "gearbox_config.h"
#include "pins.h"
#include "board_config.h"
Egs52Can::Egs52Can(const char* name, uint8_t tx_time_ms)
: AbstractCan(name, tx_time_ms)
{

View File

@ -1,7 +1,7 @@
#include "can_egs53.h"
#include "driver/twai.h"
#include "gearbox_config.h"
#include "pins.h"
#include "board_config.h"
uint8_t crcTable[256]; // For CRC only

View File

@ -1,6 +1,6 @@
#include "can_egs_basic.h"
#include "driver/twai.h"
#include "pins.h"
#include "board_config.h"
EgsBasicCan::EgsBasicCan(const char* name, uint8_t tx_time_ms)
: AbstractCan(name, tx_time_ms)

View File

@ -9,6 +9,10 @@
DATA_GEARBOX_SENSORS get_gearbox_sensors(Gearbox* g) {
DATA_GEARBOX_SENSORS ret = {};
if (g == nullptr) {
memset(&ret, 0xFF, sizeof(ret));
return ret;
}
RpmReading d;
bool b = false;
@ -35,6 +39,10 @@ DATA_GEARBOX_SENSORS get_gearbox_sensors(Gearbox* g) {
DATA_SOLENOIDS get_solenoid_data(Gearbox* gb_ptr) {
DATA_SOLENOIDS ret = {};
if (gb_ptr == nullptr) {
memset(&ret, 0xFF, sizeof(ret));
return ret;
}
ret.mpc_current = sol_mpc->get_current_avg(); //sol_mpc->get_current_estimate();
ret.spc_current = sol_spc->get_current_avg();//sol_spc->get_current_estimate();
@ -63,6 +71,10 @@ DATA_SOLENOIDS get_solenoid_data(Gearbox* gb_ptr) {
DATA_PRESSURES get_pressure_data(Gearbox* gb_ptr) {
DATA_PRESSURES ret = {};
if (gb_ptr == nullptr) {
memset(&ret, 0xFF, sizeof(ret));
return ret;
}
ret.mpc_pwm = sol_mpc->get_pwm_compensated();
ret.spc_pwm = sol_spc->get_pwm_compensated();
ret.tcc_pwm = sol_tcc->get_pwm_compensated();
@ -87,6 +99,10 @@ DATA_DMA_BUFFER dump_i2s_dma() {
DATA_CANBUS_RX get_rx_can_data(AbstractCan* can_layer) {
DATA_CANBUS_RX ret = {};
if (can_layer == nullptr) {
memset(&ret, 0xFF, sizeof(ret));
return ret;
}
uint64_t now = esp_timer_get_time() / 1000;
WheelData t = can_layer->get_rear_left_wheel(now, 250);
@ -131,6 +147,10 @@ DATA_SYS_USAGE get_sys_usage() {
SHIFT_LIVE_INFO get_shift_live_Data(AbstractCan* can_layer, Gearbox* g) {
SHIFT_LIVE_INFO ret = {};
if (can_layer == nullptr || g == nullptr) {
memset(&ret, 0xFF, sizeof(ret));
return ret;
}
ret.spc_pressure = g->pressure_mgr->get_targ_spc_pressure();
ret.mpc_pressure = g->pressure_mgr->get_targ_mpc_pressure();
@ -188,7 +208,7 @@ TCM_CORE_CONFIG get_tcm_config() {
}
uint8_t set_tcm_config(TCM_CORE_CONFIG cfg) {
ShifterPosition pos = egs_can_hal->get_shifter_position_ewm(esp_timer_get_time()/1000, 250);
ShifterPosition pos = egs_can_hal == nullptr ? ShifterPosition::SignalNotAvaliable : egs_can_hal->get_shifter_position_ewm(esp_timer_get_time()/1000, 250);
if (
pos == ShifterPosition::D || pos == ShifterPosition::MINUS || pos == ShifterPosition::PLUS || pos == ShifterPosition::R || // Stationary positions
pos == ShifterPosition::N_D || pos == ShifterPosition::P_R || pos == ShifterPosition::R_N // Intermediate positions

View File

@ -30,6 +30,7 @@ static_assert(sizeof(ShiftReport) < DIAG_CAN_MAX_SIZE-3, "Shift report is too bi
#define RLI_DMA_DUMP 0x26
#define RLI_SHIFT_LIVE 0x27
#define RLI_FW_HEADER 0x28
#define RLI_EFUSE_CONFIG 0xFD // TCM Configuration (PCB Config in EFUSE)
#define RLI_TCM_CONFIG 0xFE // TCM configuration (AKA SCN)
// Gearbox sensor struct

View File

@ -127,9 +127,33 @@ Kwp2000_server::Kwp2000_server(AbstractCan* can_layer, Gearbox* gearbox) {
this->reboot_pending = false;
this->can_layer = can_layer;
this->gearbox_ptr = gearbox;
this->can_endpoint = new CanEndpoint(can_layer);
// Start ISO-TP endpoint
xTaskCreatePinnedToCore(can_endpoint->start_iso_tp, "ISO_TP_DIAG", 8192, this->can_endpoint, 5, nullptr, 0);
if (can_layer != nullptr) {
this->can_endpoint = new CanEndpoint(can_layer);
// Start ISO-TP endpoint
xTaskCreatePinnedToCore(can_endpoint->start_iso_tp, "ISO_TP_DIAG", 8192, this->can_endpoint, 5, nullptr, 0);
} else {
this->can_endpoint = nullptr;
this->can_layer = nullptr;
}
this->supplier_id = 0x08;
if (can_layer == nullptr || gearbox == nullptr) {
this->diag_var_code = 0x0000;
} else {
switch (VEHICLE_CONFIG.egs_can_type) {
case 1:
this->diag_var_code = 0x0251;
case 2:
this->diag_var_code = 0x0251;
case 3:
this->diag_var_code = 0x0353;
default:
this->diag_var_code = 0x0000;
break;
}
}
init_perfmon();
}
@ -199,7 +223,7 @@ void Kwp2000_server::server_loop() {
if (this->usb_diag_endpoint->read_data(&this->rx_msg)) {
endpoint_was_usb = true;
read_msg = true;
} else if (this->can_endpoint->read_data(&this->rx_msg)) {
} else if (this->can_endpoint != nullptr && this->can_endpoint->read_data(&this->rx_msg)) {
endpoint_was_usb = false;
read_msg = true;
}
@ -265,7 +289,7 @@ void Kwp2000_server::server_loop() {
if (this->send_resp) {
if (endpoint_was_usb) {
this->usb_diag_endpoint->send_data(&tx_msg);
} else {
} else if (this->can_endpoint != nullptr) {
this->can_endpoint->send_data(&tx_msg);
}
this->send_resp = false;
@ -336,7 +360,7 @@ void Kwp2000_server::process_ecu_reset(uint8_t* args, uint16_t arg_len) {
} else {
// 1 arg, process the reset type
if (args[0] == 0x01 || args[1] == 0x82) {
if (!is_shifter_passive(this->can_layer)) {
if (this->can_layer != nullptr && !is_shifter_passive(this->can_layer)) {
// P or R, we CANNOT reset the ECU!
make_diag_neg_msg(SID_ECU_RESET, NRC_CONDITIONS_NOT_CORRECT_REQ_SEQ_ERROR);
return;
@ -385,9 +409,9 @@ void Kwp2000_server::process_read_ecu_ident(uint8_t* args, uint16_t arg_len) {
// ECU Software date
daimler_ident_data[7] = date.week;
daimler_ident_data[8] = date.year;
daimler_ident_data[9] = SUPPLIER_ID;
daimler_ident_data[10] = DIAG_VARIANT_CODE >> 8;
daimler_ident_data[11] = DIAG_VARIANT_CODE & 0xFF;
daimler_ident_data[9] = this->supplier_id;
daimler_ident_data[10] = this->diag_var_code >> 8;
daimler_ident_data[11] = this->diag_var_code & 0xFF;
daimler_ident_data[13] = date.year;
daimler_ident_data[14] = date.month;
daimler_ident_data[15] = date.day;
@ -397,9 +421,9 @@ void Kwp2000_server::process_read_ecu_ident(uint8_t* args, uint16_t arg_len) {
uint8_t ident_data[19];
memset(ident_data, 0x00, 19);
ident_data[0] = 0x00; // TODO ECU origin
ident_data[1] = SUPPLIER_ID;
ident_data[2] = DIAG_VARIANT_CODE >> 8;
ident_data[3] = DIAG_VARIANT_CODE & 0xFF;
ident_data[1] = this->supplier_id;
ident_data[2] = this->diag_var_code >> 8;
ident_data[3] = this->diag_var_code & 0xFF;
ident_data[5] = 0x00;// HW version
ident_data[6] = 0x00;// HW version
ident_data[7] = date.day;// SW version
@ -419,7 +443,7 @@ void Kwp2000_server::process_read_ecu_ident(uint8_t* args, uint16_t arg_len) {
} else if (args[0] == 0x88) { // VIN original
make_diag_pos_msg(SID_READ_ECU_IDENT, 0x88, (const uint8_t*)"ULTIMATENAG52ESP0", 17);
} else if (args[0] == 0x89) { // Diagnostic variant code
int d = DIAG_VARIANT_CODE;
int d = this->diag_var_code;
uint8_t b[4];
memcpy(b, &d, 4);
make_diag_pos_msg(SID_READ_ECU_IDENT, 0x89, b, 4);
@ -526,6 +550,10 @@ void Kwp2000_server::process_read_data_local_ident(uint8_t* args, uint16_t arg_l
} else if (args[0] == RLI_TCM_CONFIG) {
TCM_CORE_CONFIG r = get_tcm_config();
make_diag_pos_msg(SID_READ_DATA_LOCAL_IDENT, RLI_TCM_CONFIG, (uint8_t*)&r, sizeof(TCM_CORE_CONFIG));
} else if (args[0] == RLI_EFUSE_CONFIG) {
TCM_EFUSE_CONFIG ecfg;
EEPROM::read_efuse_config(&ecfg);
make_diag_pos_msg(SID_READ_DATA_LOCAL_IDENT, RLI_EFUSE_CONFIG, (uint8_t*)&ecfg, sizeof(TCM_EFUSE_CONFIG));
} else if (args[0] == RLI_SHIFT_LIVE) {
SHIFT_LIVE_INFO r = get_shift_live_Data(egs_can_hal, gearbox);
make_diag_pos_msg(SID_READ_DATA_LOCAL_IDENT, RLI_SHIFT_LIVE, (uint8_t*)&r, sizeof(SHIFT_LIVE_INFO));
@ -787,6 +815,20 @@ void Kwp2000_server::process_write_data_by_local_ident(uint8_t* args, uint16_t a
make_diag_neg_msg(SID_WRITE_DATA_BY_LOCAL_IDENT, res);
}
}
} else if (args[0] == RLI_EFUSE_CONFIG) {
if (arg_len-1 != sizeof(TCM_EFUSE_CONFIG)) {
make_diag_neg_msg(SID_WRITE_DATA_BY_LOCAL_IDENT, NRC_SUB_FUNC_NOT_SUPPORTED_INVALID_FORMAT);
} else {
// TCM Core config size ok
TCM_EFUSE_CONFIG cfg;
memcpy(&cfg, &args[1], sizeof(TCM_EFUSE_CONFIG));
bool res = EEPROM::write_efuse_config(&cfg);
if (res == true) {
make_diag_pos_msg(SID_WRITE_DATA_BY_LOCAL_IDENT, RLI_TCM_CONFIG, nullptr, 0);
} else {
make_diag_neg_msg(SID_WRITE_DATA_BY_LOCAL_IDENT, NRC_GENERAL_REJECT);
}
}
} else {
make_diag_neg_msg(SID_WRITE_DATA_BY_LOCAL_IDENT, NRC_REQUEST_OUT_OF_RANGE);
}

View File

@ -13,23 +13,6 @@
#include "esp32/spiram.h"
#include "flasher.h"
// Ident data
#ifdef EGS53_MODE
#define SUPPLIER_ID 0x08 // Simens
#define DIAG_VARIANT_CODE 0x0353 // DiagVersion53_EGS53
#endif
#ifdef EGS52_MODE
#define SUPPLIER_ID 0x08 // Simens
#define DIAG_VARIANT_CODE 0x0251 // DiagVersion51_EGS52
#endif
#ifdef EGS51_MODE
#define SUPPLIER_ID 0x08 // Simens
#define DIAG_VARIANT_CODE 0x000 // DiagVersion51_EGS52
#endif
#define PROCESSOR_TYPE
#define COMM_MATRIX_VERSION 0x0101 // 01.01
#define CAN_DRIVER_VERSION 0x0101 // 01.01
@ -115,6 +98,8 @@ class Kwp2000_server {
void run_solenoid_test();
xTaskHandle* running_routine;
Flasher* flash_handler = nullptr;
uint8_t supplier_id;
uint16_t diag_var_code;
};
#endif //_KWP_H__

View File

@ -18,12 +18,10 @@
// CAN LAYERS
#include "canbus/can_egs_basic.h"
#ifdef BOARD_V2
#include "canbus/can_egs51.h"
#endif
#include "canbus/can_egs52.h"
#include "canbus/can_egs53.h"
#include "pins.h"
#include "board_config.h"
Kwp2000_server* diag_server;
@ -53,17 +51,13 @@ SPEAKER_POST_CODE setup_tcm()
}
spkr = new Speaker(pcb_gpio_matrix->spkr_pin);
int egs_mode = 0;
if (!EEPROM::init_eeprom()) {
return SPEAKER_POST_CODE::EEPROM_FAIL;
}
switch (egs_mode) {
#if defined(BOARD_V2)
switch (VEHICLE_CONFIG.egs_can_type) {
case 1:
egs_can_hal = new Egs51Can("EGS51", 20); // EGS51 CAN Abstraction layer
break;
#endif
case 2:
egs_can_hal = new Egs52Can("EGS52", 20); // EGS52 CAN Abstraction layer
break;
@ -72,6 +66,7 @@ SPEAKER_POST_CODE setup_tcm()
break;
default:
// Unknown (Fallback to basic CAN)
ESP_LOGE("INIT", "ERROR. CAN Mode not set, falling back to basic CAN (Diag only!)");
egs_can_hal = new EgsBasicCan("EGSBASIC", 20);
break;
}
@ -207,8 +202,15 @@ const char* post_code_to_str(SPEAKER_POST_CODE s) {
extern "C" void app_main(void)
{
// Set all pointers
gearbox = nullptr;
egs_can_hal = nullptr;
pressure_manager = nullptr;
SPEAKER_POST_CODE s = setup_tcm();
xTaskCreate(err_beep_loop, "PCSPKR", 2048, (void*)s, 2, nullptr);
// Now spin up the KWP2000 server (last thing)
diag_server = new Kwp2000_server(egs_can_hal, gearbox);
xTaskCreatePinnedToCore(Kwp2000_server::start_kwp_server, "KWP2000", 32*1024, diag_server, 5, nullptr, 0);
if (s != SPEAKER_POST_CODE::INIT_OK) {
while(true) {
ESP_LOG_LEVEL(ESP_LOG_ERROR, "INIT", "TCM INIT ERROR (%s)! CANNOT START TCM!", post_code_to_str(s));
@ -217,9 +219,6 @@ extern "C" void app_main(void)
} else { // INIT OK!
xTaskCreate(input_manager, "INPUT_MANAGER", 8192, nullptr, 5, nullptr);
}
// Now spin up the KWP2000 server (last thing)
diag_server = new Kwp2000_server(egs_can_hal, gearbox);
xTaskCreatePinnedToCore(Kwp2000_server::start_kwp_server, "KWP2000", 32*1024, diag_server, 5, nullptr, 0);
}
#endif // UNIT_TEST

View File

@ -127,26 +127,22 @@ bool EEPROM::read_core_config(TCM_CORE_CONFIG* dest) {
if (e == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOG_LEVEL(ESP_LOG_WARN, "EEPROM", "SCN Config not found. Creating a new one");
TCM_CORE_CONFIG s = {
#ifdef LARGE_NAG
.is_large_nag = 1,
#else
.is_large_nag = 0,
#endif
.diff_ratio = DIFF_RATIO,
.wheel_circumference = TYRE_SIZE_MM,
#ifdef FOUR_MATIC
.is_four_matic = 1,
.transfer_case_high_ratio = TC_RATIO_HIGH,
.transfer_case_low_ratio = TC_RATIO_LOW,
#else
.diff_ratio = 1000,
.wheel_circumference = 2850,
.is_four_matic = 0,
.transfer_case_high_ratio = 1000,
.transfer_case_low_ratio = 1000,
#endif
.default_profile = 0, // Standard
.red_line_rpm_diesel = 4500, // Safe for diesels, petrol-heads can change this!
.red_line_rpm_petrol = 6000,
.engine_type = 0 // Diesel by default - TODO We should read this via CAN
.engine_type = 0,
.egs_can_type = 0,
.shifter_style = 0,
.io_0_usage = 0,
.input_sensor_pulses_per_rev = 1,
.output_pulse_width_per_kmh = 1,
.gen_mosfet_purpose = 0,
};
e = nvs_set_blob(handle, NVS_KEY_SCN_CONFIG, &s, sizeof(s));
if (e != ESP_OK) {
@ -194,10 +190,48 @@ bool EEPROM::read_efuse_config(TCM_EFUSE_CONFIG* dest) {
esp_efuse_read_field_blob(ESP_EFUSE_M_WEEK, &dest->manufacture_week, 8);
esp_efuse_read_field_blob(ESP_EFUSE_M_MONTH, &dest->manufacture_month, 8);
esp_efuse_read_field_blob(ESP_EFUSE_M_YEAR, &dest->manufacture_year, 8);
ESP_LOG_LEVEL(ESP_LOG_INFO, "READ EFUSE", "CONFIG:Board Ver: %d, Week %d (%02d/%02d/%02d)", dest->board_ver, dest->manufacture_day, dest->manufacture_week, dest->manufacture_month, dest->manufacture_year);
ESP_LOG_LEVEL(ESP_LOG_INFO, "READ EFUSE", "CONFIG:Board Ver: V1.%d, Week %d (%02d/%02d/%02d)", dest->board_ver, dest->manufacture_week, dest->manufacture_day, dest->manufacture_month, dest->manufacture_year);
return true;
}
bool EEPROM::write_efuse_config(TCM_EFUSE_CONFIG* dest) {
if (dest == nullptr) {
return false;
}
if (dest->manufacture_month > 12 || dest->manufacture_month == 0) {
return false;
}
if (dest->manufacture_day > 31 || dest->manufacture_day == 0) {
return false;
}
if (dest->manufacture_week > 52 || dest->manufacture_week == 0) {
return false;
}
if (dest->manufacture_year < 22) {
return false;
}
if (dest->board_ver == 0 || dest->board_ver > 3) {
return false;
}
if (esp_efuse_write_field_blob(ESP_EFUSE_BOARD_VER, &dest->board_ver, 8) != ESP_OK) {
return false;
}
if (esp_efuse_write_field_blob(ESP_EFUSE_M_DAY, &dest->manufacture_day, 8) != ESP_OK) {
return false;
}
if (esp_efuse_write_field_blob(ESP_EFUSE_M_WEEK, &dest->manufacture_week, 8) != ESP_OK) {
return false;
}
if (esp_efuse_write_field_blob(ESP_EFUSE_M_MONTH, &dest->manufacture_month, 8) != ESP_OK) {
return false;
}
if (esp_efuse_write_field_blob(ESP_EFUSE_M_YEAR, &dest->manufacture_year, 8) != ESP_OK) {
return false;
}
return true;
}
TCM_CORE_CONFIG VEHICLE_CONFIG = {};
TCM_EFUSE_CONFIG BOARD_CONFIG = {};
nvs_handle_t MAP_NVS_HANDLE = {};

View File

@ -29,6 +29,12 @@ typedef struct {
uint16_t red_line_rpm_diesel;
uint16_t red_line_rpm_petrol;
uint8_t engine_type; // 0 for diesel, 1 for petrol
uint8_t egs_can_type;
uint8_t shifter_style;
uint8_t io_0_usage;
uint8_t input_sensor_pulses_per_rev;
uint8_t output_pulse_width_per_kmh;
uint8_t gen_mosfet_purpose;
} __attribute__ ((packed)) TCM_CORE_CONFIG;
@ -55,6 +61,7 @@ namespace EEPROM {
bool read_core_config(TCM_CORE_CONFIG* dest);
bool save_core_config(TCM_CORE_CONFIG* write);
bool read_efuse_config(TCM_EFUSE_CONFIG* dest);
bool write_efuse_config(TCM_EFUSE_CONFIG* dest);
bool read_nvs_map_data(const char* map_name, int16_t* dest, const int16_t* default_map, size_t map_element_count);

View File

@ -1,75 +0,0 @@
#ifndef __PINS_H_
#define __PINS_H_
#include <driver/gpio.h>
class BoardGpioMatrix {
public:
BoardGpioMatrix();
gpio_num_t can_tx_pin;
gpio_num_t can_rx_pin;
gpio_num_t spkr_pin;
gpio_num_t vsense_pin;
gpio_num_t atf_pin;
gpio_num_t n3_pin;
gpio_num_t n2_pin;
gpio_num_t io_pin; // Only on 1.3 and newer
gpio_num_t y3_sense;
gpio_num_t y3_pwm;
gpio_num_t y4_sense;
gpio_num_t y4_pwm;
gpio_num_t y5_sense;
gpio_num_t y5_pwm;
gpio_num_t mpc_sense;
gpio_num_t mpc_pwm;
gpio_num_t spc_sense;
gpio_num_t spc_pwm;
gpio_num_t tcc_sense;
gpio_num_t tcc_pwm;
gpio_num_t i2c_sda; // Only on 1.2 and newer
gpio_num_t i2c_scl; // Only on 1.2 and newer
};
/**
* @brief GPIO Matrix for the Red beta PCB (V1.1 12/12/21)
*
* NOTE: This will be removed from the code base once all beta boards have been replaced
*
*/
class BoardV11GpioMatrix: public BoardGpioMatrix {
public:
BoardV11GpioMatrix();
};
/**
* @brief GPIO Matrix for the Gen 1 production PCB (V1.2 07/07/22)
*
*/
class BoardV12GpioMatrix: public BoardGpioMatrix {
public:
BoardV12GpioMatrix();
};
/**
* @brief GPIO Matrix for the Gen 2 production PCB (V1.3 29/11/22)
* NOTE: This PCB is in development, so its matrix can change
*/
class BoardV13GpioMatrix: public BoardGpioMatrix {
public:
BoardV13GpioMatrix();
};
extern BoardGpioMatrix* pcb_gpio_matrix;
#endif

View File

@ -7,9 +7,9 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "pins.h"
#include "board_config.h"
#include "macros.h"
#include "pins.h"
#include "nvs/eeprom_config.h"
#define PULSES_PER_REV 60 // N2 and N3 are 60 pulses per revolution
#define PCNT_H_LIM 1
@ -19,82 +19,13 @@
const pcnt_unit_t PCNT_N2_RPM = PCNT_UNIT_0;
const pcnt_unit_t PCNT_N3_RPM = PCNT_UNIT_1;
typedef struct {
// Voltage in mV
uint16_t v;
// ATF Temp in degrees C * 10
int temp;
} temp_reading_t;
#define NUM_TEMP_POINTS 22
#ifdef BOARD_V2
#define ADC_CHANNEL_VBATT_V12 adc2_channel_t::ADC2_CHANNEL_8
#define ADC_CHANNEL_ATF_V12 adc2_channel_t::ADC2_CHANNEL_7
const static temp_reading_t atf_temp_lookup[NUM_TEMP_POINTS] = {
// mV, Temp(x10)
// mV Values are calibrated on 3.45V rail
// as that is how much the ATF sensor power gets
{725, -400},
{784, -300},
{842, -200},
{900, -100},
{957, 0},
{1013, 100},
{1068, 200},
{1123, 300},
{1177, 400},
{1230, 500},
{1281, 600},
{1332, 700},
{1384, 800},
{1438, 900},
{1488, 1000},
{1538, 1100},
{1587, 1200},
{1636, 1300},
{1685, 1400},
{1732, 1500},
{1779, 1600},
{1826, 1700}
};
#define ADC_CHANNEL_VBATT adc2_channel_t::ADC2_CHANNEL_8
#define ADC_CHANNEL_ATF adc2_channel_t::ADC2_CHANNEL_7
#else
const static temp_reading_t atf_temp_lookup[NUM_TEMP_POINTS] = {
// mV, Temp(x10)
// mV Values are calibrated on 3.45V rail
// as that is how much the ATF sensor power gets
{446, -400},
{461, -300},
{476, -200},
{491, -100},
{507, 0},
{523, 100},
{540, 200},
{557, 300},
{574, 400},
{592, 500},
{610, 600},
{629, 700},
{648, 800},
{669, 900},
{690, 1000},
{711, 1100},
{732, 1200},
{755, 1300},
{778, 1400},
{802, 1500},
{814, 1600},
{851, 1700}
};
#define ADC_CHANNEL_VBATT adc2_channel_t::ADC2_CHANNEL_8
#define ADC_CHANNEL_ATF adc2_channel_t::ADC2_CHANNEL_9
#endif
#define ADC_CHANNEL_VBATT_V11 adc2_channel_t::ADC2_CHANNEL_8
#define ADC_CHANNEL_ATF_V11 adc2_channel_t::ADC2_CHANNEL_9
#define ADC2_ATTEN ADC_ATTEN_11db
#define ADC2_WIDTH ADC_WIDTH_12Bit
@ -173,8 +104,8 @@ bool Sensors::init_sensors(){
CHECK_ESP_FUNC(gpio_set_pull_mode(pcb_gpio_matrix->n3_pin, GPIO_PULLUP_ONLY), "Failed to set PIN_N3 to Input! %s", esp_err_to_name(res))
// Configure ADC2 for analog readings
CHECK_ESP_FUNC(adc2_config_channel_atten(ADC_CHANNEL_VBATT, ADC_ATTEN_11db), "Failed to set ADC attenuation for PIN_ATF! %s", esp_err_to_name(res))
CHECK_ESP_FUNC(adc2_config_channel_atten(ADC_CHANNEL_ATF, ADC_ATTEN_11db), "Failed to set ADC attenuation for PIN_VBATT! %s", esp_err_to_name(res))
CHECK_ESP_FUNC(adc2_config_channel_atten(pcb_gpio_matrix->sensor_data.atf_channel, ADC_ATTEN_11db), "Failed to set ADC attenuation for PIN_ATF! %s", esp_err_to_name(res))
CHECK_ESP_FUNC(adc2_config_channel_atten(pcb_gpio_matrix->sensor_data.batt_channel, ADC_ATTEN_11db), "Failed to set ADC attenuation for PIN_VBATT! %s", esp_err_to_name(res))
// Characterise ADC2
esp_adc_cal_characterize(adc_unit_t::ADC_UNIT_2, adc_atten_t::ADC_ATTEN_DB_11, ADC2_WIDTH, 0, &adc2_cal_atf);
@ -276,7 +207,7 @@ bool Sensors::read_input_rpm(RpmReading* dest, bool check_sanity) {
bool Sensors::read_vbatt(uint16_t *dest){
uint32_t v;
if (esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_8, &adc2_cal_vbatt, &v) != ESP_OK) {
if (esp_adc_cal_get_voltage(pcb_gpio_matrix->sensor_data.adc_batt, &adc2_cal_vbatt, &v) != ESP_OK) {
return false;
} else {
// Vin = Vout(R1+R2)/R2
@ -287,35 +218,30 @@ bool Sensors::read_vbatt(uint16_t *dest){
// Returns ATF temp in *C
bool Sensors::read_atf_temp(int16_t* dest) {
uint32_t avg = 0;
#ifdef BOARD_V2
static const float ATF_TEMP_CORR = 1.0;
#else
uint32_t raw = 0;
static const float ATF_TEMP_CORR = 0.8;
#endif
#ifdef BOARD_V2
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_7, &adc2_cal_atf, &avg);
if (res != ESP_OK) {
return false;
}
#else
#define NUM_ATF_SAMPLES 5
for (uint8_t i = 0; i < NUM_ATF_SAMPLES; i++) {
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_9, &adc2_cal_atf, &raw);
uint32_t avg = 0;
float ATF_TEMP_CORR = BOARD_CONFIG.board_ver >= 2 ? 1.0 : 0.8;
if (BOARD_CONFIG.board_ver >= 2) {
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_7, &adc2_cal_atf, &avg);
if (res != ESP_OK) {
//ESP_LOG_LEVEL(ESP_LOG_WARN, "READ_ATF", "Failed to query ATF temp. %s", esp_err_to_name(res));
return false;
}
avg += raw;
} else {
uint32_t raw = 0;
for (uint8_t i = 0; i < 5; i++) {
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_9, &adc2_cal_atf, &raw);
if (res != ESP_OK) {
return false;
}
avg += raw;
}
avg /= 5;
}
avg /= NUM_ATF_SAMPLES;
#endif
if (avg >= 3000) {
return false; // Parking lock engaged, cannot read.
}
const temp_reading_t* atf_temp_lookup = pcb_gpio_matrix->sensor_data.atf_calibration_curve;
if (avg <= atf_temp_lookup[0].v) {
*dest = (int16_t)((float)atf_temp_lookup[0].temp * ATF_TEMP_CORR);
return true;
@ -338,11 +264,7 @@ uint32_t avg = 0;
bool Sensors::parking_lock_engaged(bool* dest){
uint32_t raw;
#ifdef BOARD_V2
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_7, &adc2_cal_atf, &raw);
#else
esp_err_t res = esp_adc_cal_get_voltage(adc_channel_t::ADC_CHANNEL_9, &adc2_cal_atf, &raw);
#endif
esp_err_t res = esp_adc_cal_get_voltage(pcb_gpio_matrix->sensor_data.adc_atf, &adc2_cal_atf, &raw);
if (res != ESP_OK) {
return false;
} else {

View File

@ -1,7 +1,7 @@
#include "solenoids.h"
#include "esp_log.h"
#include "esp_adc_cal.h"
#include "pins.h"
#include "board_config.h"
#include "../sensors.h"
#include "soc/syscon_periph.h"
#include "soc/i2s_periph.h"
@ -76,11 +76,7 @@ uint16_t Solenoid::get_current() {
if (v <= adc1_cal.coeff_b) {
v = 0; // Too small
}
#ifdef BOARD_V2
return v;
#else
return v*2;
#endif
return v*pcb_gpio_matrix->sensor_data.current_sense_multi;
}
uint16_t Solenoid::get_pwm_raw()
@ -104,11 +100,7 @@ uint16_t Solenoid::get_current_avg()
if (v <= adc1_cal.coeff_b) {
v = 0; // Too small
}
#ifdef BOARD_V2
return v;
#else
return v*2;
#endif
return v*pcb_gpio_matrix->sensor_data.current_sense_multi;
}
void Solenoid::__write_pwm() {

View File

@ -1,5 +1,5 @@
#include "speaker.h"
#include "pins.h"
#include "board_config.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"