From 4276c380e6624e99c886edefc637b5e6ccc0828b Mon Sep 17 00:00:00 2001 From: Nigel Armstrong Date: Mon, 1 Apr 2019 22:45:00 -0700 Subject: [PATCH] Additional Power saving (#170) * Only turn on wifi if not eon * Dont disable ESP in early * Allow CAN to be turned off - CAN is turned off via timeout - CAN is turned on when either try to transmit or can is received - If only transmit is asleep, all messages should send okay - If receive is alseep, will miss first message while waking up - Sometimes will report error on second message while CAN perif wakes up - Saves 130mW! * Power Saver Mode - Gray Panda power consumption 650mw -> 325mW - Turns off CAN, GMLAN, LIN, GPS when no activity for 10s - No acitvity is no CAN send, CAN Recv, Write to GPS * Fix power_saving to better turn off can - On some cars when the can is turned off, it triggers a wakeup. Delaying the automatic wakeup seems to fix this * Don't save power in pedal * Cleanup power saving --- board/drivers/can.h | 50 +++++++++++--- board/gpio.h | 2 +- board/main.c | 8 +++ board/pedal/main.c | 2 +- board/power_saving.h | 160 +++++++++++++++++++++++++++++++++++++++++++ python/__init__.py | 4 ++ 6 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 board/power_saving.h diff --git a/board/drivers/can.h b/board/drivers/can.h index b837094c9a0d38..d685ce601b9e8d 100644 --- a/board/drivers/can.h +++ b/board/drivers/can.h @@ -23,6 +23,11 @@ can_buffer(tx2_q, 0x100) can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q}; #endif +#ifdef PANDA +// Forward declare +void power_save_reset_timer(); +#endif + // ********************* interrupt safe queue ********************* int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { @@ -213,7 +218,7 @@ void can_init(uint8_t can_number) { CAN->FMR &= ~(CAN_FMR_FINIT); // enable certain CAN interrupts - CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0; + CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE; switch (can_number) { case 0: @@ -293,7 +298,6 @@ void can_set_gmlan(int bus) { void can_sce(CAN_TypeDef *CAN) { enter_critical_section(); - can_err_cnt += 1; #ifdef DEBUG if (CAN==CAN1) puts("CAN1: "); if (CAN==CAN2) puts("CAN2: "); @@ -315,16 +319,32 @@ void can_sce(CAN_TypeDef *CAN) { uint8_t can_number = CAN_NUM_FROM_CANIF(CAN); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); - if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) { - can_autobaud_speed_increment(can_number); - can_set_speed(can_number); - } - // clear current send - CAN->TSR |= CAN_TSR_ABRQ0; - CAN->MSR &= ~(CAN_MSR_ERRI); - CAN->MSR = CAN->MSR; + if (CAN->MSR & CAN_MSR_WKUI) { + //Waking from sleep + #ifdef DEBUG + puts("WAKE\n"); + #endif + set_can_enable(CAN, 1); + CAN->MSR &= ~(CAN_MSR_WKUI); + CAN->MSR = CAN->MSR; +#ifdef PANDA + power_save_reset_timer(); +#endif + } else { + can_err_cnt += 1; + + + if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) { + can_autobaud_speed_increment(can_number); + can_set_speed(can_number); + } + // clear current send + CAN->TSR |= CAN_TSR_ABRQ0; + CAN->MSR &= ~(CAN_MSR_ERRI); + CAN->MSR = CAN->MSR; + } exit_critical_section(); } @@ -332,6 +352,9 @@ void can_sce(CAN_TypeDef *CAN) { void process_can(uint8_t can_number) { if (can_number == 0xff) return; +#ifdef PANDA + power_save_reset_timer(); +#endif enter_critical_section(); @@ -375,6 +398,13 @@ void process_can(uint8_t can_number) { } if (can_pop(can_queues[bus_number], &to_send)) { + if (CAN->MCR & CAN_MCR_SLEEP) { + set_can_enable(CAN, 1); + CAN->MCR &= ~(CAN_MCR_SLEEP); + CAN->MCR |= CAN_MCR_INRQ; + while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); + CAN->MCR &= ~(CAN_MCR_INRQ); + } can_tx_cnt += 1; // only send if we have received a packet CAN->sTxMailBox[0].TDLR = to_send.RDLR; diff --git a/board/gpio.h b/board/gpio.h index 7bd24ecbb7c32d..061adf49f357a2 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -120,6 +120,7 @@ void periph_init() { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; @@ -475,4 +476,3 @@ void early() { enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; } } - diff --git a/board/main.c b/board/main.c index 8ee1bb0c8c830c..248fdea68c0cb4 100644 --- a/board/main.c +++ b/board/main.c @@ -20,6 +20,8 @@ #include "drivers/spi.h" #include "drivers/timer.h" +#include "power_saving.h" + // ***************************** fan ***************************** @@ -141,6 +143,7 @@ void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) { uart_ring *ur = get_ring_by_number(usbdata[0]); if (!ur) return; if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) { + if (ur == &esp_ring) power_save_reset_timer(); for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i])); } } @@ -572,6 +575,9 @@ int main() { #ifdef PANDA spi_init(); #endif +#ifdef DEBUG + puts("DEBUG ENABLED\n"); +#endif // set PWM fan_init(); @@ -581,6 +587,8 @@ int main() { __enable_irq(); + power_save_init(); + // if the error interrupt is enabled to quickly when the CAN bus is active // something bad happens and you can't connect to the device over USB delay(10000000); diff --git a/board/pedal/main.c b/board/pedal/main.c index 13a221a871fafc..6b55ca780c283f 100644 --- a/board/pedal/main.c +++ b/board/pedal/main.c @@ -295,6 +295,7 @@ int main() { puts("**** INTERRUPTS ON ****\n"); __enable_irq(); + // main pedal loop while (1) { pedal(); @@ -302,4 +303,3 @@ int main() { return 0; } - diff --git a/board/power_saving.h b/board/power_saving.h new file mode 100644 index 00000000000000..cc03c880794b80 --- /dev/null +++ b/board/power_saving.h @@ -0,0 +1,160 @@ +#define POWER_SAVE_STATUS_DISABLED 0 +//Moving to enabled, but can wakeup not yet enabled +#define POWER_SAVE_STATUS_SWITCHING 1 +#define POWER_SAVE_STATUS_ENABLED 2 + +volatile int power_save_status = POWER_SAVE_STATUS_DISABLED; + +void power_save_enable(void) { + power_save_status = POWER_SAVE_STATUS_SWITCHING; + puts("Saving power\n"); + //Turn off can transciever + set_can_enable(CAN1, 0); + set_can_enable(CAN2, 0); +#ifdef PANDA + set_can_enable(CAN3, 0); +#endif + + //Turn off GMLAN + set_gpio_output(GPIOB, 14, 0); + set_gpio_output(GPIOB, 15, 0); + +#ifdef PANDA + //Turn off LIN K + if (revision == PANDA_REV_C) { + set_gpio_output(GPIOB, 7, 0); // REV C + } else { + set_gpio_output(GPIOB, 4, 0); // REV AB + } + // LIN L + set_gpio_output(GPIOA, 14, 0); +#endif + + if (is_grey_panda) { + char* UBLOX_SLEEP_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; + int len = 12; + uart_ring *ur = get_ring_by_number(1); + for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i])); + } + + //Setup timer for can enable + TIM6->PSC = 48-1; // tick on 1 us + + TIM6->ARR = 12; // 12us + // Enable, One-Pulse Mode, Only overflow interrupt + TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS; + TIM6->EGR = TIM_EGR_UG; + TIM6->CR1 |= TIM_CR1_CEN; +} + +void power_save_enable_can_wake(void) { + // CAN Automatic Wake must be done a little while after the sleep + // On some cars turning off the can transciver can trigger the wakeup + power_save_status = POWER_SAVE_STATUS_ENABLED; + puts("Turning can off\n"); + CAN1->MCR |= CAN_MCR_SLEEP; + CAN1->MCR |= CAN_MCR_AWUM; + + CAN2->MCR |= CAN_MCR_SLEEP; + CAN2->MCR |= CAN_MCR_AWUM; +#ifdef PANDA + CAN3->MCR |= CAN_MCR_SLEEP; + CAN3->MCR |= CAN_MCR_AWUM; +#endif + + //set timer back + TIM6->PSC = 48000-1; // tick on 1 ms + TIM6->ARR = 10000; // 10s + // Enable, One-Pulse Mode, Only overflow interrupt + TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_URS; + TIM6->EGR = TIM_EGR_UG; +} + +void power_save_disable(void) { + power_save_status = POWER_SAVE_STATUS_DISABLED; + puts("not Saving power\n"); + TIM6->CR1 |= TIM_CR1_CEN; //Restart timer + TIM6->CNT = 0; + + //Turn on can + set_can_enable(CAN1, 1); + set_can_enable(CAN2, 1); + +#ifdef PANDA + set_can_enable(CAN3, 1); +#endif + + //Turn on GMLAN + set_gpio_output(GPIOB, 14, 1); + set_gpio_output(GPIOB, 15, 1); + +#ifdef PANDA + //Turn on LIN K + if (revision == PANDA_REV_C) { + set_gpio_output(GPIOB, 7, 1); // REV C + } else { + set_gpio_output(GPIOB, 4, 1); // REV AB + } + // LIN L + set_gpio_output(GPIOA, 14, 1); +#endif + + if (is_grey_panda) { + char* UBLOX_WAKE_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; + int len = 12; + uart_ring *ur = get_ring_by_number(1); + for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); + } + + //set timer back + TIM6->PSC = 48000-1; // tick on 1 ms + TIM6->ARR = 10000; // 10s + // Enable, One-Pulse Mode, Only overflow interrupt + TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS; + TIM6->EGR = TIM_EGR_UG; + TIM6->CR1 |= TIM_CR1_CEN; +} + + + +// Reset timer when activity +void power_save_reset_timer() { + TIM6->CNT = 0; + if (power_save_status != POWER_SAVE_STATUS_DISABLED){ + power_save_disable(); + } +} + +void power_save_init(void) { + puts("Saving power init\n"); + TIM6->PSC = 48000-1; // tick on 1 ms + + + TIM6->ARR = 10000; // 10s + // Enable, One-Pulse Mode, Only overflow interrupt + TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS; + TIM6->EGR = TIM_EGR_UG; + NVIC_EnableIRQ(TIM6_DAC_IRQn); + puts("Saving power init done\n"); + TIM6->DIER = TIM_DIER_UIE; + TIM6->CR1 |= TIM_CR1_CEN; +} + +void TIM6_DAC_IRQHandler(void) { + puts("TIM6 "); + putui(TIM6->SR); + puts("\n"); + //Timeout switch to power saving mode. + if (TIM6->SR & TIM_SR_UIF) { + TIM6->SR = 0; +#ifdef EON + if (power_save_status == POWER_SAVE_STATUS_DISABLED) { + power_save_enable(); + } else if (power_save_status == POWER_SAVE_STATUS_SWITCHING) { + power_save_enable_can_wake(); + } +#endif + } else { + TIM6->CR1 |= TIM_CR1_CEN; + } +} diff --git a/python/__init__.py b/python/__init__.py index b3610e6c3f9970..5370427c049e24 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -390,6 +390,10 @@ def set_can_loopback(self, enable): # set can loopback mode for all buses self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'') + def set_can_enable(self, bus_num, enable): + # sets the can transciever enable pin + self._handle.controlWrite(Panda.REQUEST_OUT, 0xf4, int(bus_num), int(enable), b'') + def set_can_speed_kbps(self, bus, speed): self._handle.controlWrite(Panda.REQUEST_OUT, 0xde, bus, int(speed*10), b'')