diff --git a/CHANGELOG b/CHANGELOG index bc7114b6f..836529d85 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +=== FW 3.64 === +* Added support for HW60_MK3 +* Disable shutdown sampling when the watchdog runs slowly. + === FW 3.63 === * NRF remote power meter is now unaffected by temperature decrease and speed limits. * Added LZO compression support to firmware upload, making firmware updates 30% - 50% faster. diff --git a/applications/app_uartcomm.c b/applications/app_uartcomm.c index 7f7279b8d..0cd83672e 100644 --- a/applications/app_uartcomm.c +++ b/applications/app_uartcomm.c @@ -71,7 +71,11 @@ static void send_packet(unsigned char *data, unsigned int len) { #ifdef HW_UART_P_DEV if (from_p_uart) { if (uart_p_is_running) { +#ifdef HW_UART_P_DEV_TX + sdWrite(&HW_UART_P_DEV_TX, data, len); +#else sdWrite(&HW_UART_P_DEV, data, len); +#endif } } else { if (uart_is_running) { @@ -117,6 +121,11 @@ void app_uartcomm_start_permanent(void) { } sdStart(&HW_UART_P_DEV, &uart_p_cfg); + +#ifdef HW_UART_P_DEV_TX + sdStart(&HW_UART_P_DEV_TX, &uart_p_cfg); +#endif + palSetPadMode(HW_UART_P_TX_PORT, HW_UART_P_TX_PIN, PAL_MODE_ALTERNATE(HW_UART_P_GPIO_AF) | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUDR_PULLUP); diff --git a/conf_general.h b/conf_general.h index 413ee4f79..8ebe5dac5 100644 --- a/conf_general.h +++ b/conf_general.h @@ -67,6 +67,9 @@ // Benjamins first HW60 PCB with PB5 and PB6 swapped //#define HW60_VEDDER_FIRST_PCB +// Mark3 version of HW60 with power switch and separate NRF UART. +#define HW60_IS_MK3 + #define HW_SOURCE "hw_60.c" #define HW_HEADER "hw_60.h" diff --git a/hwconf/hw_60.c b/hwconf/hw_60.c index 82d23c6f9..64bb4d1b3 100644 --- a/hwconf/hw_60.c +++ b/hwconf/hw_60.c @@ -22,9 +22,16 @@ #include "stm32f4xx_conf.h" #include "utils.h" #include "drv8301.h" +#include "terminal.h" +#include "commands.h" +#include "mc_interface.h" // Variables static volatile bool i2c_running = false; +#ifdef HW60_IS_MK3 +static mutex_t shutdown_mutex; +static float bt_diff = 0.0; +#endif // I2C configuration static const I2CConfig i2cfg = { @@ -33,7 +40,16 @@ static const I2CConfig i2cfg = { STD_DUTY_CYCLE }; +#ifdef HW60_IS_MK3 +static void terminal_shutdown_now(int argc, const char **argv); +static void terminal_button_test(int argc, const char **argv); +#endif + void hw_init_gpio(void) { +#ifdef HW60_IS_MK3 + chMtxObjectInit(&shutdown_mutex); +#endif + // GPIO clock enable RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); @@ -110,9 +126,25 @@ void hw_init_gpio(void) { palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); +#ifndef HW60_IS_MK3 palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); +#endif drv8301_init(); + +#ifdef HW60_IS_MK3 + terminal_register_command_callback( + "shutdown", + "Shutdown VESC now.", + 0, + terminal_shutdown_now); + + terminal_register_command_callback( + "test_button", + "Try sampling the shutdown button", + 0, + terminal_button_test); +#endif } void hw_setup_adc_channels(void) { @@ -242,3 +274,44 @@ void hw_try_restore_i2c(void) { i2cReleaseBus(&HW_I2C_DEV); } } + +#ifdef HW60_IS_MK3 +bool hw_sample_shutdown_button(void) { + chMtxLock(&shutdown_mutex); + + bt_diff = 0.0; + + for (int i = 0;i < 3;i++) { + palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_INPUT_ANALOG); + chThdSleep(5); + float val1 = ADC_VOLTS(ADC_IND_SHUTDOWN); + chThdSleepMilliseconds(1); + float val2 = ADC_VOLTS(ADC_IND_SHUTDOWN); + palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); + chThdSleepMilliseconds(1); + + bt_diff += (val1 - val2); + } + + chMtxUnlock(&shutdown_mutex); + + return (bt_diff > 0.12); +} + +static void terminal_shutdown_now(int argc, const char **argv) { + (void)argc; + (void)argv; + DISABLE_GATE(); + HW_SHUTDOWN_HOLD_OFF(); +} + +static void terminal_button_test(int argc, const char **argv) { + (void)argc; + (void)argv; + + for (int i = 0;i < 40;i++) { + commands_printf("BT: %d %.2f", HW_SAMPLE_SHUTDOWN(), (double)bt_diff); + chThdSleepMilliseconds(100); + } +} +#endif diff --git a/hwconf/hw_60.h b/hwconf/hw_60.h index 79c478971..2c1952617 100644 --- a/hwconf/hw_60.h +++ b/hwconf/hw_60.h @@ -20,13 +20,19 @@ #ifndef HW_60_H_ #define HW_60_H_ +#ifdef HW60_IS_MK3 +#define HW_NAME "60_MK3" +#else #define HW_NAME "60" +#endif // HW properties #define HW_HAS_DRV8301 #define HW_HAS_3_SHUNTS -#define HW_HAS_PERMANENT_NRF #define HW_HAS_PHASE_SHUNTS +#ifndef HW60_IS_MK3 +#define HW_HAS_PERMANENT_NRF +#endif // Macros #ifdef HW60_VEDDER_FIRST_PCB @@ -48,6 +54,22 @@ #define CURRENT_FILTER_ON() palSetPad(GPIOD, 2) #define CURRENT_FILTER_OFF() palClearPad(GPIOD, 2) +#ifdef HW60_IS_MK3 +// Shutdown pin +#define HW_SHUTDOWN_GPIO GPIOC +#define HW_SHUTDOWN_PIN 5 +#define HW_SHUTDOWN_HOLD_ON() palSetPad(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN) +#define HW_SHUTDOWN_HOLD_OFF() palClearPad(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN) +#define HW_SAMPLE_SHUTDOWN() hw_sample_shutdown_button() + +// Hold shutdown pin early to wake up on short pulses +#define HW_EARLY_INIT() palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); \ + HW_SHUTDOWN_HOLD_ON(); \ + palSetPadMode(GPIOD, 2, \ + PAL_MODE_OUTPUT_PUSHPULL | \ + PAL_STM32_OSPEED_HIGHEST); \ + CURRENT_FILTER_ON() +#else // Switch on current filter if a permanent // NRF24 cannot be found, as the later // HW60 has changed one of the permanent NRF @@ -57,6 +79,7 @@ PAL_MODE_OUTPUT_PUSHPULL | \ PAL_STM32_OSPEED_HIGHEST); \ CURRENT_FILTER_ON() +#endif /* * ADC Vector @@ -71,7 +94,7 @@ * 7: IN6 ADC_EXT2 * 8: IN3 TEMP_PCB * 9: IN14 TEMP_MOTOR - * 10: IN15 ADC_EXT3 + * 10: IN15 ADC_EXT3, Shutdown on MK3 * 11: IN13 AN_IN * 12: Vrefint * 13: IN0 SENS1 @@ -95,6 +118,9 @@ #define ADC_IND_TEMP_MOS 8 #define ADC_IND_TEMP_MOTOR 9 #define ADC_IND_VREFINT 12 +#ifdef HW60_IS_MK3 +#define ADC_IND_SHUTDOWN 10 +#endif // ADC macros and settings @@ -154,6 +180,18 @@ #define HW_UART_RX_PORT GPIOB #define HW_UART_RX_PIN 11 +#ifdef HW60_IS_MK3 +// Permanent UART Peripheral (for NRF51) +#define HW_UART_P_BAUD 115200 +#define HW_UART_P_DEV SD4 +#define HW_UART_P_DEV_TX SD5 // UART for TX, due to mistake below +#define HW_UART_P_GPIO_AF GPIO_AF_UART4 +#define HW_UART_P_TX_PORT GPIOC +#define HW_UART_P_TX_PIN 12 // This is a mistake in the HW. We have to use a hack to use UART5. +#define HW_UART_P_RX_PORT GPIOC +#define HW_UART_P_RX_PIN 11 +#endif + // ICU Peripheral for servo decoding #define HW_USE_SERVO_TIM4 #define HW_ICU_TIMER TIM4 @@ -190,6 +228,7 @@ #define HW_ENC_TIM_ISR_CH TIM3_IRQn #define HW_ENC_TIM_ISR_VEC TIM3_IRQHandler +#ifndef HW60_IS_MK3 // NRF pins #define NRF_PORT_CSN GPIOB #define NRF_PIN_CSN 12 @@ -199,6 +238,7 @@ #define NRF_PIN_MOSI 3 #define NRF_PORT_MISO GPIOD #define NRF_PIN_MISO 2 +#endif // SPI pins #define HW_SPI_DEV SPID1 @@ -213,6 +253,16 @@ #define HW_SPI_PIN_MISO 6 // SPI for DRV8301 +#ifndef HW60_IS_MK3 +#define DRV8301_MOSI_GPIO GPIOB +#define DRV8301_MOSI_PIN 4 +#define DRV8301_MISO_GPIO GPIOB +#define DRV8301_MISO_PIN 3 +#define DRV8301_SCK_GPIO GPIOC +#define DRV8301_SCK_PIN 10 +#define DRV8301_CS_GPIO GPIOC +#define DRV8301_CS_PIN 9 +#else #define DRV8301_MOSI_GPIO GPIOC #define DRV8301_MOSI_PIN 12 #define DRV8301_MISO_GPIO GPIOC @@ -221,6 +271,7 @@ #define DRV8301_SCK_PIN 10 #define DRV8301_CS_GPIO GPIOC #define DRV8301_CS_PIN 9 +#endif // MPU9250 #define MPU9X50_SDA_GPIO GPIOB @@ -229,6 +280,14 @@ #define MPU9X50_SCL_PIN 15 #define IMU_FLIP +#ifdef HW60_IS_MK3 +// NRF SWD +#define NRF5x_SWDIO_GPIO GPIOB +#define NRF5x_SWDIO_PIN 12 +#define NRF5x_SWCLK_GPIO GPIOA +#define NRF5x_SWCLK_PIN 4 +#endif + // Measurement macros #define ADC_V_L1 ADC_Value[ADC_IND_SENS1] #define ADC_V_L2 ADC_Value[ADC_IND_SENS2] @@ -261,4 +320,9 @@ #define HW_LIM_DUTY_MAX 0.0, 0.99 #define HW_LIM_TEMP_FET -40.0, 110.0 +// Functions +#ifdef HW60_IS_MK3 +bool hw_sample_shutdown_button(void); +#endif + #endif /* HW_60_H_ */ diff --git a/hwconf/hw_hd.c b/hwconf/hw_hd.c index 0b3d35141..92b9565cb 100644 --- a/hwconf/hw_hd.c +++ b/hwconf/hw_hd.c @@ -266,7 +266,7 @@ bool hw_sample_shutdown_button(void) { bt_diff = 0.0; for (int i = 0;i < 3;i++) { - palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_INPUT_ANALOG); chThdSleep(5); float val1 = ADC_VOLTS(ADC_IND_SHUTDOWN); chThdSleepMilliseconds(1); diff --git a/hwconf/hw_hd.h b/hwconf/hw_hd.h index d9066518e..a4a18334b 100644 --- a/hwconf/hw_hd.h +++ b/hwconf/hw_hd.h @@ -147,7 +147,7 @@ #define HW_UART_RX_PORT GPIOB #define HW_UART_RX_PIN 11 -// Permanent UART Peripheral (for NRF51) +// Permanent UART Peripheral (for NRF52) #define HW_UART_P_BAUD 115200 #define HW_UART_P_DEV SD4 #define HW_UART_P_GPIO_AF GPIO_AF_UART4 diff --git a/mcuconf.h b/mcuconf.h index e7e0dfec3..6e91a297f 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -275,7 +275,7 @@ #define STM32_SERIAL_USE_USART2 FALSE #define STM32_SERIAL_USE_USART3 TRUE #define STM32_SERIAL_USE_UART4 TRUE -#define STM32_SERIAL_USE_UART5 FALSE +#define STM32_SERIAL_USE_UART5 TRUE #define STM32_SERIAL_USE_USART6 TRUE #define STM32_SERIAL_USART1_PRIORITY 3 #define STM32_SERIAL_USART2_PRIORITY 3 diff --git a/shutdown.c b/shutdown.c index aa8d906bf..24ce429c8 100644 --- a/shutdown.c +++ b/shutdown.c @@ -26,12 +26,17 @@ bool volatile m_button_pressed = false; static volatile float m_inactivity_time = 0.0; static THD_WORKING_AREA(shutdown_thread_wa, 128); +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_thread, arg); void shutdown_init(void) { + chMtxObjectInit(&m_sample_mutex); chThdCreateStatic(shutdown_thread_wa, sizeof(shutdown_thread_wa), NORMALPRIO, shutdown_thread, NULL); + m_init_done = true; } void shutdown_reset_timer(void) { @@ -46,6 +51,16 @@ float shutdown_get_inactivity_time(void) { return m_inactivity_time; } +void shutdown_set_sampling_disabled(bool disabled) { + if (!m_init_done) { + return; + } + + chMtxLock(&m_sample_mutex); + m_sampling_disabled = disabled; + chMtxUnlock(&m_sample_mutex); +} + static THD_FUNCTION(shutdown_thread, arg) { (void)arg; @@ -59,12 +74,21 @@ static THD_FUNCTION(shutdown_thread, arg) { float dt = (float)chVTTimeElapsedSinceX(last_iteration_time) / (float)CH_CFG_ST_FREQUENCY; last_iteration_time = chVTGetSystemTimeX(); - const app_configuration *conf = app_get_configuration(); + chMtxLock(&m_sample_mutex); + + if (m_sampling_disabled) { + chMtxUnlock(&m_sample_mutex); + chThdSleepMilliseconds(10); + continue; + } bool sample = HW_SAMPLE_SHUTDOWN(); + chMtxUnlock(&m_sample_mutex); bool clicked = m_button_pressed && !sample; m_button_pressed = sample; + 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. diff --git a/shutdown.h b/shutdown.h index d06db373c..6f9fa94da 100644 --- a/shutdown.h +++ b/shutdown.h @@ -25,11 +25,13 @@ #include "conf_general.h" #ifdef HW_SHUTDOWN_HOLD_ON -#define SHUTDOWN_RESET() shutdown_reset_timer() -#define SHUTDOWN_BUTTON_PRESSED shutdown_button_pressed() +#define SHUTDOWN_RESET() shutdown_reset_timer() +#define SHUTDOWN_BUTTON_PRESSED shutdown_button_pressed() +#define SHUTDOWN_SET_SAMPLING_DISABLED(d) shutdown_set_sampling_disabled(d) #else #define SHUTDOWN_RESET() -#define SHUTDOWN_BUTTON_PRESSED false +#define SHUTDOWN_BUTTON_PRESSED false +#define SHUTDOWN_SET_SAMPLING_DISABLED(d) #endif // Fucntions @@ -37,5 +39,6 @@ void shutdown_init(void); void shutdown_reset_timer(void); bool shutdown_button_pressed(void); float shutdown_get_inactivity_time(void); +void shutdown_set_sampling_disabled(bool disabled); #endif /* SHUTDOWN_H_ */ diff --git a/timeout.c b/timeout.c index 1239d3df5..112b43bed 100644 --- a/timeout.c +++ b/timeout.c @@ -20,6 +20,7 @@ #include "timeout.h" #include "mc_interface.h" #include "stm32f4xx_conf.h" +#include "shutdown.h" // Private variables static volatile bool init_done = false; @@ -106,6 +107,10 @@ void timeout_configure_IWDT_slowest(void) { return; } + // As we expect to lock the CPU for a couple of ms make sure that shutdown is not sampling the button input, + // as that can cause a shutdown. + SHUTDOWN_SET_SAMPLING_DISABLED(true); + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) { // Continue to kick the dog IWDG_ReloadCounter(); @@ -129,6 +134,8 @@ void timeout_configure_IWDT(void) { return; } + SHUTDOWN_SET_SAMPLING_DISABLED(false); + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) { // Continue to kick the dog IWDG_ReloadCounter();