From 5a5ccfb4c36b886e1ea9c4c34170bec908236a52 Mon Sep 17 00:00:00 2001 From: Benjamin Vedder Date: Mon, 4 May 2015 23:25:43 +0200 Subject: [PATCH] ADC app added, nunchuk RPM filter, FW version added, feedback on appconf and mcconf set --- applications/app.c | 11 ++ applications/app.h | 4 + applications/app_adc.c | 336 +++++++++++++++++++++++++++++++++++ applications/app_nunchuk.c | 18 +- applications/app_ppm.c | 6 +- applications/applications.mk | 1 + comm_can.c | 7 +- commands.c | 54 ++++++ conf_general.c | 21 ++- conf_general.h | 4 + datatypes.h | 39 +++- 11 files changed, 492 insertions(+), 9 deletions(-) create mode 100644 applications/app_adc.c diff --git a/applications/app.c b/applications/app.c index b9bf3a07..1bb80931 100644 --- a/applications/app.c +++ b/applications/app.c @@ -39,6 +39,10 @@ void app_init(app_configuration *conf) { app_ppm_start(); break; + case APP_ADC: + app_adc_start(); + break; + case APP_UART: hw_stop_i2c(); app_uartcomm_start(); @@ -50,6 +54,12 @@ void app_init(app_configuration *conf) { app_uartcomm_start(); break; + case APP_ADC_UART: + hw_stop_i2c(); + app_adc_start(); + app_uartcomm_start(); + break; + case APP_NUNCHUK: app_nunchuk_start(); break; @@ -87,6 +97,7 @@ const app_configuration* app_get_configuration(void) { void app_set_configuration(app_configuration *conf) { appconf = *conf; app_ppm_configure(&appconf.app_ppm_conf); + app_adc_configure(&appconf.app_adc_conf); app_uartcomm_configure(appconf.app_uart_baudrate); app_nunchuk_configure(&appconf.app_chuk_conf); } diff --git a/applications/app.h b/applications/app.h index 173e4083..77151697 100644 --- a/applications/app.h +++ b/applications/app.h @@ -35,6 +35,10 @@ void app_set_configuration(app_configuration *conf); // Standard apps void app_ppm_start(void); void app_ppm_configure(ppm_config *conf); +void app_adc_start(void); +void app_adc_configure(adc_config *conf); +float app_adc_get_decoded_level(void); +float app_adc_get_voltage(void); void app_uartcomm_start(void); void app_uartcomm_configure(uint32_t baudrate); void app_nunchuk_start(void); diff --git a/applications/app_adc.c b/applications/app_adc.c new file mode 100644 index 00000000..4fb9882c --- /dev/null +++ b/applications/app_adc.c @@ -0,0 +1,336 @@ +/* + Copyright 2012-2015 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/* + * app_adc.c + * + * Created on: 1 may 2015 + * Author: benjamin + */ + +#include "app.h" + +#include "ch.h" +#include "hal.h" +#include "stm32f4xx_conf.h" +#include "mcpwm.h" +#include "timeout.h" +#include "utils.h" +#include "comm_can.h" +#include "hw.h" +#include + +// Settings +#define MAX_CAN_AGE 0.1 +#define MIN_MS_WITHOUT_POWER 500 +#define FILTER_SAMPLES 5 + +// Threads +static msg_t adc_thread(void *arg); +static WORKING_AREA(adc_thread_wa, 1024); + +// Private variables +static volatile adc_config config; +static volatile float ms_without_power = 0; +static volatile float decoded_level = 0.0; +static volatile float read_voltage = 0.0; + +void app_adc_configure(adc_config *conf) { + config = *conf; + ms_without_power = 0.0; +} + +void app_adc_start(void) { + chThdCreateStatic(adc_thread_wa, sizeof(adc_thread_wa), NORMALPRIO, adc_thread, NULL); +} + +float app_adc_get_decoded_level(void) { + return decoded_level; +} + +float app_adc_get_voltage(void) { + return read_voltage; +} + +static msg_t adc_thread(void *arg) { + (void)arg; + + chRegSetThreadName("APP_ADC"); + + // Set servo pin as an input with pullup + palSetPadMode(HW_ICU_GPIO, HW_ICU_PIN, PAL_MODE_INPUT_PULLUP); + + for(;;) { + // Sleep for a time according to the specified rate + systime_t sleep_time = CH_FREQUENCY / config.update_rate_hz; + + // At least one tick should be slept to not block the other threads + if (sleep_time == 0) { + sleep_time = 1; + } + chThdSleep(sleep_time); + + // Read the external ADC pin and convert the value to a voltage. + float pwr = (float)ADC_Value[ADC_IND_EXT]; + pwr /= 4095; + pwr *= V_REG; + + read_voltage = pwr; + + // Optionally apply a mean value filter + if (config.use_filter) { + static float filter_buffer[FILTER_SAMPLES]; + static int filter_ptr = 0; + + filter_buffer[filter_ptr++] = pwr; + if (filter_ptr >= FILTER_SAMPLES) { + filter_ptr = 0; + } + + pwr = 0.0; + for (int i = 0;i < FILTER_SAMPLES;i++) { + pwr += filter_buffer[i]; + } + pwr /= FILTER_SAMPLES; + } + + // Map and truncate the read voltage + pwr = utils_map(pwr, config.voltage_start, config.voltage_end, 0.0, 1.0); + utils_truncate_number(&pwr, 0.0, 1.0); + + // Optionally invert the read voltage + if (config.voltage_inverted) { + pwr = 1.0 - pwr; + } + + decoded_level = pwr; + + // Read the servo pin and optionally invert it. + bool button_val = !palReadPad(HW_ICU_GPIO, HW_ICU_PIN); + if (config.button_inverted) { + button_val = !button_val; + } + + switch (config.ctrl_type) { + case ADC_CTRL_TYPE_CURRENT_REV_CENTER: + case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_CENTER: + case ADC_CTRL_TYPE_DUTY_REV_CENTER: + // Scale the voltage and set 0 at the center + pwr *= 2.0; + pwr -= 1.0; + break; + + case ADC_CTRL_TYPE_CURRENT_REV_BUTTON: + case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON: + case ADC_CTRL_TYPE_DUTY_REV_BUTTON: + // Invert the voltage if the button is pressed + if (button_val) { + pwr = -pwr; + } + break; + + default: + break; + } + + // Apply a deadband + utils_deadband(&pwr, config.hyst, 1.0); + + float current = 0; + bool current_mode = false; + bool current_mode_brake = false; + const volatile mc_configuration *mcconf = mcpwm_get_configuration(); + bool send_duty = false; + + // Use the filtered and mapped voltage for control according to the configuration. + switch (config.ctrl_type) { + case ADC_CTRL_TYPE_CURRENT: + case ADC_CTRL_TYPE_CURRENT_REV_CENTER: + case ADC_CTRL_TYPE_CURRENT_REV_BUTTON: + current_mode = true; + if (pwr >= 0.0) { + current = pwr * mcconf->l_current_max; + } else { + current = pwr * fabsf(mcconf->l_current_min); + } + + if (fabsf(pwr) < 0.001) { + ms_without_power += (1000.0 * (float)sleep_time) / (float)CH_FREQUENCY; + } + break; + + case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_CENTER: + case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON: + current_mode = true; + if (pwr >= 0.0) { + current = pwr * mcconf->l_current_max; + } else { + current = fabsf(pwr * mcconf->l_current_min); + current_mode_brake = true; + } + + if (pwr < 0.001) { + ms_without_power += (1000.0 * (float)sleep_time) / (float)CH_FREQUENCY; + } + break; + + case ADC_CTRL_TYPE_DUTY: + case ADC_CTRL_TYPE_DUTY_REV_CENTER: + case ADC_CTRL_TYPE_DUTY_REV_BUTTON: + if (fabsf(pwr) < 0.001) { + ms_without_power += (1000.0 * (float)sleep_time) / (float)CH_FREQUENCY; + } + + if (!(ms_without_power < MIN_MS_WITHOUT_POWER && config.safe_start)) { + mcpwm_set_duty(pwr); + send_duty = true; + } + break; + + default: + continue; + } + + // If safe start is enabled and the output has not been zero for long enough + if (ms_without_power < MIN_MS_WITHOUT_POWER && config.safe_start) { + static int pulses_without_power_before = 0; + if (ms_without_power == pulses_without_power_before) { + ms_without_power = 0; + } + pulses_without_power_before = ms_without_power; + mcpwm_set_current(0.0); + continue; + } + + // Reset timeout + timeout_reset(); + + // Find lowest RPM (for traction control) + float rpm_local = mcpwm_get_rpm(); + float rpm_lowest = rpm_local; + if (config.multi_esc) { + for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) { + can_status_msg *msg = comm_can_get_status_msg_index(i); + + if (msg->id >= 0 && UTILS_AGE_S(msg->rx_time) < MAX_CAN_AGE) { + float rpm_tmp = msg->rpm; + + if (fabsf(rpm_tmp) < fabsf(rpm_lowest)) { + rpm_lowest = rpm_tmp; + } + } + } + } + + // Optionally send the duty cycles to the other ESCs seen on the CAN-bus + if (send_duty && config.multi_esc) { + float duty = mcpwm_get_duty_cycle_now(); + + for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) { + can_status_msg *msg = comm_can_get_status_msg_index(i); + + if (msg->id >= 0 && UTILS_AGE_S(msg->rx_time) < MAX_CAN_AGE) { + comm_can_set_duty(msg->id, duty); + } + } + } + + if (current_mode) { + if (current_mode_brake) { + mcpwm_set_brake_current(current); + + // Send brake command to all ESCs seen recently on the CAN bus + for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) { + can_status_msg *msg = comm_can_get_status_msg_index(i); + + if (msg->id >= 0 && UTILS_AGE_S(msg->rx_time) < MAX_CAN_AGE) { + comm_can_set_current_brake(msg->id, current); + } + } + } else { + // Apply soft RPM limit + if (rpm_lowest > config.rpm_lim_end && current > 0.0) { + current = mcconf->cc_min_current; + } else if (rpm_lowest > config.rpm_lim_start && current > 0.0) { + current = utils_map(rpm_lowest, config.rpm_lim_start, config.rpm_lim_end, current, mcconf->cc_min_current); + } else if (rpm_lowest < -config.rpm_lim_end && current < 0.0) { + current = mcconf->cc_min_current; + } else if (rpm_lowest < -config.rpm_lim_start && current < 0.0) { + rpm_lowest = -rpm_lowest; + current = -current; + current = utils_map(rpm_lowest, config.rpm_lim_start, config.rpm_lim_end, current, mcconf->cc_min_current); + current = -current; + rpm_lowest = -rpm_lowest; + } + + float current_out = current; + bool is_reverse = false; + if (current_out < 0.0) { + is_reverse = true; + current_out = -current_out; + current = -current; + rpm_local = -rpm_local; + rpm_lowest = -rpm_lowest; + } + + // Traction control + if (config.multi_esc) { + for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) { + can_status_msg *msg = comm_can_get_status_msg_index(i); + + if (msg->id >= 0 && UTILS_AGE_S(msg->rx_time) < MAX_CAN_AGE) { + if (config.tc) { + float rpm_tmp = msg->rpm; + if (is_reverse) { + rpm_tmp = -rpm_tmp; + } + + float diff = rpm_tmp - rpm_lowest; + current_out = utils_map(diff, 0.0, config.tc_max_diff, current, 0.0); + if (current_out < mcconf->cc_min_current) { + current_out = 0.0; + } + } + + if (is_reverse) { + comm_can_set_current(msg->id, -current_out); + } else { + comm_can_set_current(msg->id, current_out); + } + } + } + + if (config.tc) { + float diff = rpm_local - rpm_lowest; + current_out = utils_map(diff, 0.0, config.tc_max_diff, current, 0.0); + if (current_out < mcconf->cc_min_current) { + current_out = 0.0; + } + } + } + + if (is_reverse) { + mcpwm_set_current(-current_out); + } else { + mcpwm_set_current(current_out); + } + } + } + } + + return 0; +} diff --git a/applications/app_nunchuk.c b/applications/app_nunchuk.c index 19eda459..3dd07889 100644 --- a/applications/app_nunchuk.c +++ b/applications/app_nunchuk.c @@ -40,6 +40,7 @@ #define OUTPUT_ITERATION_TIME_MS 1 #define MAX_CURR_DIFFERENCE 5.0 #define MAX_CAN_AGE 0.1 +#define RPM_FILTER_SAMPLES 8 // Threads static msg_t chuk_thread(void *arg); @@ -230,12 +231,27 @@ static msg_t output_thread(void *arg) { // If c is pressed and no throttle is used, maintain the current speed with PID control static bool was_pid = false; + // Filter RPM to avoid glitches + static float filter_buffer[RPM_FILTER_SAMPLES]; + static int filter_ptr = 0; + float rpm_filtered = mcpwm_get_rpm(); + filter_buffer[filter_ptr++] = rpm_filtered; + if (filter_ptr >= RPM_FILTER_SAMPLES) { + filter_ptr = 0; + } + + rpm_filtered = 0.0; + for (int i = 0;i < RPM_FILTER_SAMPLES;i++) { + rpm_filtered += filter_buffer[i]; + } + rpm_filtered /= RPM_FILTER_SAMPLES; + if (chuck_d.bt_c && out_val == 0.0) { static float pid_rpm = 0.0; if (!was_pid) { was_pid = true; - pid_rpm = mcpwm_get_rpm(); + pid_rpm = rpm_filtered; } if ((is_reverse && pid_rpm < 0.0) || (!is_reverse && pid_rpm > 0.0)) { diff --git a/applications/app_ppm.c b/applications/app_ppm.c index 4cfbca3d..cab091ef 100644 --- a/applications/app_ppm.c +++ b/applications/app_ppm.c @@ -1,5 +1,5 @@ /* - Copyright 2012-2014 Benjamin Vedder benjamin@vedder.se + Copyright 2012-2015 Benjamin Vedder benjamin@vedder.se This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ static volatile ppm_config config; static volatile int pulses_without_power = 0; // Private functions -void update(void *p); +static void update(void *p); void app_ppm_configure(ppm_config *conf) { config = *conf; @@ -79,7 +79,7 @@ static void servodec_func(void) { chSysUnlockFromIsr(); } -void update(void *p) { +static void update(void *p) { chSysLockFromIsr(); chVTSetI(&vt, MS2ST(2), update, p); chEvtSignalI(ppm_tp, (eventmask_t) 1); diff --git a/applications/applications.mk b/applications/applications.mk index 97463b90..9ffb60cf 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -1,5 +1,6 @@ APPSRC = applications/app.c \ applications/app_ppm.c \ + applications/app_adc.c \ applications/app_sten.c \ applications/app_gurgalof.c \ applications/app_uartcomm.c \ diff --git a/comm_can.c b/comm_can.c index 6106a50a..5765a27e 100644 --- a/comm_can.c +++ b/comm_can.c @@ -239,7 +239,12 @@ static msg_t cancom_status_thread(void *arg) { comm_can_transmit(app_get_configuration()->controller_id | ((uint32_t)CAN_PACKET_STATUS << 8), buffer, send_index); } - chThdSleep(CH_FREQUENCY / app_get_configuration()->send_can_status_rate_hz); + systime_t sleep_time = CH_FREQUENCY / app_get_configuration()->send_can_status_rate_hz; + if (sleep_time == 0) { + sleep_time = 1; + } + + chThdSleep(sleep_time); } return 0; diff --git a/commands.c b/commands.c index d9e08135..b9e204fa 100644 --- a/commands.c +++ b/commands.c @@ -115,6 +115,14 @@ void commands_process_packet(unsigned char *data, unsigned char len) { len--; switch (packet_id) { + case COMM_FW_VERSION: + ind = 0; + send_buffer[ind++] = COMM_FW_VERSION; + send_buffer[ind++] = FW_VERSION_MAJOR; + send_buffer[ind++] = FW_VERSION_MINOR; + commands_send_packet(send_buffer, ind); + break; + case COMM_GET_VALUES: ind = 0; send_buffer[ind++] = COMM_GET_VALUES; @@ -241,6 +249,10 @@ void commands_process_packet(unsigned char *data, unsigned char len) { conf_general_store_mc_configuration(&mcconf); mcpwm_set_configuration(&mcconf); + + ind = 0; + send_buffer[ind++] = COMM_SET_MCCONF; + commands_send_packet(send_buffer, ind); break; case COMM_GET_MCCONF: @@ -328,6 +340,21 @@ void commands_process_packet(unsigned char *data, unsigned char len) { appconf.app_ppm_conf.tc = data[ind++]; appconf.app_ppm_conf.tc_max_diff = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.ctrl_type = data[ind++]; + appconf.app_adc_conf.hyst = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.voltage_start = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.voltage_end = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.use_filter = data[ind++]; + appconf.app_adc_conf.safe_start = data[ind++]; + appconf.app_adc_conf.button_inverted = data[ind++]; + appconf.app_adc_conf.voltage_inverted = data[ind++]; + appconf.app_adc_conf.rpm_lim_start = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.rpm_lim_end = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.multi_esc = data[ind++]; + appconf.app_adc_conf.tc = data[ind++]; + appconf.app_adc_conf.tc_max_diff = (float)buffer_get_int32(data, &ind) / 1000.0; + appconf.app_adc_conf.update_rate_hz = buffer_get_uint16(data, &ind); + appconf.app_uart_baudrate = buffer_get_uint32(data, &ind); appconf.app_chuk_conf.ctrl_type = data[ind++]; @@ -343,6 +370,10 @@ void commands_process_packet(unsigned char *data, unsigned char len) { conf_general_store_app_configuration(&appconf); app_set_configuration(&appconf); timeout_configure(appconf.timeout_msec, appconf.timeout_brake_current); + + ind = 0; + send_buffer[ind++] = COMM_SET_MCCONF; + commands_send_packet(send_buffer, ind); break; case COMM_GET_APPCONF: @@ -371,6 +402,21 @@ void commands_process_packet(unsigned char *data, unsigned char len) { send_buffer[ind++] = appconf.app_ppm_conf.tc; buffer_append_int32(send_buffer, (int32_t)(appconf.app_ppm_conf.tc_max_diff * 1000.0), &ind); + send_buffer[ind++] = appconf.app_adc_conf.ctrl_type; + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.hyst * 1000.0), &ind); + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.voltage_start * 1000.0), &ind); + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.voltage_end * 1000.0), &ind); + send_buffer[ind++] = appconf.app_adc_conf.use_filter; + send_buffer[ind++] = appconf.app_adc_conf.safe_start; + send_buffer[ind++] = appconf.app_adc_conf.button_inverted; + send_buffer[ind++] = appconf.app_adc_conf.voltage_inverted; + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.rpm_lim_start * 1000.0), &ind); + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.rpm_lim_end * 1000.0), &ind); + send_buffer[ind++] = appconf.app_adc_conf.multi_esc; + send_buffer[ind++] = appconf.app_adc_conf.tc; + buffer_append_int32(send_buffer, (int32_t)(appconf.app_adc_conf.tc_max_diff * 1000.0), &ind); + buffer_append_uint16(send_buffer, appconf.app_adc_conf.update_rate_hz, &ind); + buffer_append_uint32(send_buffer, appconf.app_uart_baudrate, &ind); send_buffer[ind++] = appconf.app_chuk_conf.ctrl_type; @@ -426,6 +472,14 @@ void commands_process_packet(unsigned char *data, unsigned char len) { commands_send_packet(send_buffer, ind); break; + case COMM_GET_DECODED_ADC: + ind = 0; + send_buffer[ind++] = COMM_GET_DECODED_ADC; + buffer_append_int32(send_buffer, (int32_t)(app_adc_get_decoded_level() * 1000000.0), &ind); + buffer_append_int32(send_buffer, (int32_t)(app_adc_get_voltage() * 1000000.0), &ind); + commands_send_packet(send_buffer, ind); + break; + case COMM_GET_DECODED_CHUK: ind = 0; send_buffer[ind++] = COMM_GET_DECODED_CHUK; diff --git a/conf_general.c b/conf_general.c index 1ad07e43..bce7641e 100644 --- a/conf_general.c +++ b/conf_general.c @@ -152,19 +152,34 @@ void conf_general_read_app_configuration(app_configuration *conf) { conf->app_to_use = APP_NONE; - conf->app_ppm_conf.ctrl_type = PPM_CTRL_TYPE_CURRENT; + conf->app_ppm_conf.ctrl_type = PPM_CTRL_TYPE_NONE; conf->app_ppm_conf.pid_max_erpm = 15000; conf->app_ppm_conf.hyst = 0.15; conf->app_ppm_conf.pulse_start = 1.0; conf->app_ppm_conf.pulse_end = 2.0; conf->app_ppm_conf.median_filter = false; - conf->app_ppm_conf.safe_start = false; + conf->app_ppm_conf.safe_start = true; conf->app_ppm_conf.rpm_lim_start = 150000.0; conf->app_ppm_conf.rpm_lim_end = 200000.0; - conf->app_ppm_conf.multi_esc = true; + conf->app_ppm_conf.multi_esc = false; conf->app_ppm_conf.tc = false; conf->app_ppm_conf.tc_max_diff = 3000.0; + conf->app_adc_conf.ctrl_type = ADC_CTRL_TYPE_NONE; + conf->app_adc_conf.hyst = 0.15; + conf->app_adc_conf.voltage_start = 0.9; + conf->app_adc_conf.voltage_end = 3.0; + conf->app_adc_conf.use_filter = true; + conf->app_adc_conf.safe_start = true; + conf->app_adc_conf.button_inverted = false; + conf->app_adc_conf.voltage_inverted = false; + conf->app_adc_conf.rpm_lim_start = 150000; + conf->app_adc_conf.rpm_lim_end = 200000; + conf->app_adc_conf.multi_esc = false; + conf->app_adc_conf.tc = false; + conf->app_adc_conf.tc_max_diff = 3000.0; + conf->app_adc_conf.update_rate_hz = 500; + conf->app_uart_baudrate = 115200; conf->app_chuk_conf.ctrl_type = CHUK_CTRL_TYPE_CURRENT; diff --git a/conf_general.h b/conf_general.h index d715eb6f..82421d72 100644 --- a/conf_general.h +++ b/conf_general.h @@ -25,6 +25,10 @@ #ifndef CONF_GENERAL_H_ #define CONF_GENERAL_H_ +// Software version +#define FW_VERSION_MAJOR 1 +#define FW_VERSION_MINOR 0 + #include "datatypes.h" /* diff --git a/datatypes.h b/datatypes.h index 2953b5f1..a7c616ee 100644 --- a/datatypes.h +++ b/datatypes.h @@ -145,8 +145,10 @@ typedef struct { typedef enum { APP_NONE = 0, APP_PPM, + APP_ADC, APP_UART, APP_PPM_UART, + APP_ADC_UART, APP_NUNCHUK, APP_NRF, APP_CUSTOM @@ -179,6 +181,36 @@ typedef struct { float tc_max_diff; } ppm_config; +// ADC control types +typedef enum { + ADC_CTRL_TYPE_NONE = 0, + ADC_CTRL_TYPE_CURRENT, + ADC_CTRL_TYPE_CURRENT_REV_CENTER, + ADC_CTRL_TYPE_CURRENT_REV_BUTTON, + ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_CENTER, + ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON, + ADC_CTRL_TYPE_DUTY, + ADC_CTRL_TYPE_DUTY_REV_CENTER, + ADC_CTRL_TYPE_DUTY_REV_BUTTON +} adc_control_type; + +typedef struct { + adc_control_type ctrl_type; + float hyst; + float voltage_start; + float voltage_end; + bool use_filter; + bool safe_start; + bool button_inverted; + bool voltage_inverted; + float rpm_lim_start; + float rpm_lim_end; + bool multi_esc; + bool tc; + float tc_max_diff; + uint32_t update_rate_hz; +} adc_config; + // Nunchuk control types typedef enum { CHUK_CTRL_TYPE_NONE = 0, @@ -212,6 +244,9 @@ typedef struct { // PPM application settings ppm_config app_ppm_conf; + // ADC application settings + adc_config app_adc_conf; + // UART application settings uint32_t app_uart_baudrate; @@ -221,7 +256,8 @@ typedef struct { // Communication commands typedef enum { - COMM_GET_VALUES = 0, + COMM_FW_VERSION = 0, + COMM_GET_VALUES, COMM_SET_DUTY, COMM_SET_CURRENT, COMM_SET_CURRENT_BRAKE, @@ -242,6 +278,7 @@ typedef enum { COMM_REBOOT, COMM_ALIVE, COMM_GET_DECODED_PPM, + COMM_GET_DECODED_ADC, COMM_GET_DECODED_CHUK, COMM_FORWARD_CAN } COMM_PACKET_ID;