Merge pull request #681 from JohnSpintend/master

Update hw_ubox_100_core.c
This commit is contained in:
Benjamin Vedder 2023-12-06 12:57:25 +01:00 committed by GitHub
commit efa3e7ea16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 218 additions and 1 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright 2018 Benjamin Vedder benjamin@vedder.se
BCopyright 2018 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
@ -25,6 +25,25 @@
#include <math.h>
#include "mc_interface.h"
#include "shutdown.h"
#include "app.h"
#include "conf_general.h"
#include "commands.h"
#include "timeout.h"
//UBOX uses a button to press to GND to make internal 12V regulator circuit to start work.
//And uses an IO of VESC MCU to read this button state,
//And another IO to hold internal 12V regulator's enable pin.
#define UBOX_POWER_EN_ON() do{palSetPad(GPIOA, 15);}while(0)
#define UBOX_POWER_EN_OFF() do{palClearPad(GPIOA, 15);}while(0)
#define UBOX_POWER_KEY_IO_PULL_LOW() do{palClearPad(GPIOC, 13);}while(0)
#define UBOX_POWER_KEY_IO_RELEASE() do{palSetPad(GPIOC, 13);}while(0)
#define UBOX_QUERY_POWER_KEY_IO() (palReadPad(GPIOC, 13))
void shutdown_ubox_init(void);
// Variables
static volatile bool i2c_running = false;
@ -105,6 +124,15 @@ void hw_init_gpio(void) {
palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG);
palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG);
palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG);
//POWER ON EN, and start the shut_down_ubox thread
palSetPadMode(GPIOA, 15, PAL_MODE_OUTPUT_PUSHPULL);
palSetPad(GPIOA, 15);
palSetPadMode(GPIOC, 13, PAL_MODE_OUTPUT_OPENDRAIN | PAL_MODE_INPUT_PULLUP);
UBOX_POWER_KEY_IO_RELEASE();
shutdown_ubox_init();
}
void hw_setup_adc_channels(void) {
@ -254,3 +282,192 @@ float hw100_250_get_temp(void) {
return res;
}
//Copied and modified from shutdown.c
// Private variables
static bool volatile m_button_pressed = false;
static volatile float m_inactivity_time = 0.0;
static THD_WORKING_AREA(shutdown_ubox_thread_wa, 256);
static mutex_t m_sample_mutex;
static volatile bool m_init_done = false;
static volatile bool m_sampling_disabled = false;
// Private functions
static THD_FUNCTION(shutdown_ubox_thread, arg);
void shutdown_ubox_init(void) {
chMtxObjectInit(&m_sample_mutex);
chThdCreateStatic(shutdown_ubox_thread_wa, sizeof(shutdown_ubox_thread_wa), NORMALPRIO, shutdown_ubox_thread, NULL);
m_init_done = true;
}
static bool do_shutdown_ubox(void) {
conf_general_store_backup_data();
chThdSleepMilliseconds(100);
DISABLE_GATE();
UBOX_POWER_EN_OFF();
return true;
}
typedef enum {
power_key_type_undecided = 0,
power_key_type_momentary,
power_key_type_latching,
power_key_type_other_source,
}enPOWER_KEY_TYPE;
static enPOWER_KEY_TYPE power_key_type = power_key_type_undecided;
static uint32_t power_key_pressed_ms = 0;
static bool power_key_pressed_when_power_on = false;
static THD_FUNCTION(shutdown_ubox_thread, arg) {
(void)arg;
chRegSetThreadName("Shutdown_ubox");
static bool power_key_io_released = false;
systime_t last_iteration_time = chVTGetSystemTimeX();
uint64_t odometer_old = mc_interface_get_odometer();
for(;;) {
uint8_t power_key_click = 0;
uint32_t sys_time_ms = chVTGetSystemTime() / (float)CH_CFG_ST_FREQUENCY * 1000.0f;
float dt = (float)chVTTimeElapsedSinceX(last_iteration_time) / (float)CH_CFG_ST_FREQUENCY;
last_iteration_time = chVTGetSystemTimeX();
//Check power button.
//Because the low level of power key is about 1V, high is 3.3v by its hardware design.
//This 1.0V low signal voltage maybe can not to make the MCU to recognize it as 0, so it needs a workaround.
//The principle is: to check if the IO be pulled up from 0V to 3.3V by internal pull-up resistor,
//if yes, the power key is not pressing. The 0V is implemented by the assistance of IO's open drain pull down.
if(power_key_io_released == false) {
power_key_io_released = true;
UBOX_POWER_KEY_IO_RELEASE(); //Release the open drain configured IO and wait 10ms to let the internal resistor
//to pulls the line up, next time to check the IO pin register.
} else {
if(UBOX_QUERY_POWER_KEY_IO() == 0) {
if(power_key_pressed_ms < 1000 * 60) {
power_key_pressed_ms += 20;//
}
} else {
if((power_key_pressed_ms > 50) && (power_key_pressed_ms < 500)) {
power_key_click = 1;
}
power_key_pressed_ms = 0;
}
power_key_io_released = false;
UBOX_POWER_KEY_IO_PULL_LOW();//Pre-pull down the open drain configured IO, to make this IO read as 0
}
if(power_key_type == power_key_type_undecided) {
if(sys_time_ms < 1000) {
if(power_key_pressed_ms > 100) {
power_key_pressed_when_power_on = true;
}
} else {
if(power_key_pressed_when_power_on == false) {
power_key_type = power_key_type_other_source;
} else {
if(power_key_pressed_ms == 0) {
power_key_type = power_key_type_momentary;
} else if(power_key_pressed_ms > 2000) {
power_key_type = power_key_type_latching;
}
}
}
UBOX_POWER_EN_ON();
} else if(power_key_type == power_key_type_momentary) {
m_button_pressed = (bool)(power_key_pressed_ms > 2000);
bool clicked = (bool)(power_key_pressed_ms > 1000);
const app_configuration *conf = app_get_configuration();
// Note: When the gates are enabled, the push to start function
// will prevent the regulator from shutting down. Therefore, the
// gate driver has to be disabled.
switch (conf->shutdown_mode) {
case SHUTDOWN_MODE_ALWAYS_OFF:
//When the power button being pushed accidently, the regulator will working
//Inactive after 10 seconds, MCU cancels the enable signal, regulator shuts down if button released.
m_inactivity_time += dt;
if (m_inactivity_time >= 10.0f) {
do_shutdown_ubox();
}
break;
case SHUTDOWN_MODE_ALWAYS_ON:
m_inactivity_time += dt;
// Without a shutdown switch use inactivity timer to estimate
// when device is stopped. Check also distance between store
// to prevent excessive flash write cycles.
if (m_inactivity_time >= SHUTDOWN_SAVE_BACKUPDATA_TIMEOUT) {
shutdown_reset_timer();
// If at least 1km was done then we can store data
if((mc_interface_get_odometer()-odometer_old) >= 1000) {
conf_general_store_backup_data();
odometer_old = mc_interface_get_odometer();
}
}
UBOX_POWER_EN_ON();
break;
case SHUTDOWN_MODE_TOGGLE_BUTTON_ONLY:
if(clicked) {
do_shutdown_ubox();
}
break;
default: break;
}
if (conf->shutdown_mode >= SHUTDOWN_MODE_OFF_AFTER_10S) {
m_inactivity_time += dt;
float shutdown_timeout = 0.0;
switch (conf->shutdown_mode) {
case SHUTDOWN_MODE_OFF_AFTER_10S: shutdown_timeout = 10.0; break;
case SHUTDOWN_MODE_OFF_AFTER_1M: shutdown_timeout = 60.0; break;
case SHUTDOWN_MODE_OFF_AFTER_5M: shutdown_timeout = 60.0 * 5.0; break;
case SHUTDOWN_MODE_OFF_AFTER_10M: shutdown_timeout = 60.0 * 10.0; break;
case SHUTDOWN_MODE_OFF_AFTER_30M: shutdown_timeout = 60.0 * 30.0; break;
case SHUTDOWN_MODE_OFF_AFTER_1H: shutdown_timeout = 60.0 * 60.0; break;
case SHUTDOWN_MODE_OFF_AFTER_5H: shutdown_timeout = 60.0 * 60.0 * 5.0; break;
default: break;
}
if (m_inactivity_time >= shutdown_timeout) {
do_shutdown_ubox();
}
} else {
//Because SHUTDOWN_MODE_ALWAYS_OFF's implementation will check m_inactivity_time.
if(conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) {
m_inactivity_time = 0.0;
}
}
if(power_key_pressed_ms > 2000) {
do_shutdown_ubox();
}
} else {
m_inactivity_time += dt;
// Without a shutdown switch use inactivity timer to estimate
// when device is stopped. Check also distance between store
// to prevent excessive flash write cycles.
if (m_inactivity_time >= SHUTDOWN_SAVE_BACKUPDATA_TIMEOUT) {
shutdown_reset_timer();
// If at least 1km was done then we can store data
if((mc_interface_get_odometer()-odometer_old) >= 1000) {
conf_general_store_backup_data();
odometer_old = mc_interface_get_odometer();
}
}
UBOX_POWER_EN_OFF();//In latching button mode, cancel the MCU's enable signal to regulator,
//there for, when power button released, regulator shuts down.
}
timeout_reset();
chThdSleepMilliseconds(10);
}
}