Skip to content

Commit

Permalink
Additional Power saving (#170)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
legonigel committed Apr 2, 2019
1 parent 62d4219 commit 4276c38
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 12 deletions.
50 changes: 40 additions & 10 deletions board/drivers/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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: ");
Expand All @@ -315,23 +319,42 @@ 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();
}

// ***************************** CAN *****************************

void process_can(uint8_t can_number) {
if (can_number == 0xff) return;
#ifdef PANDA
power_save_reset_timer();
#endif

enter_critical_section();

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion board/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -475,4 +476,3 @@ void early() {
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
}
}

8 changes: 8 additions & 0 deletions board/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "drivers/spi.h"
#include "drivers/timer.h"

#include "power_saving.h"


// ***************************** fan *****************************

Expand Down Expand Up @@ -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]));
}
}
Expand Down Expand Up @@ -572,6 +575,9 @@ int main() {
#ifdef PANDA
spi_init();
#endif
#ifdef DEBUG
puts("DEBUG ENABLED\n");
#endif

// set PWM
fan_init();
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion board/pedal/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,11 @@ int main() {
puts("**** INTERRUPTS ON ****\n");
__enable_irq();


// main pedal loop
while (1) {
pedal();
}

return 0;
}

160 changes: 160 additions & 0 deletions board/power_saving.h
Original file line number Diff line number Diff line change
@@ -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;
}
}
4 changes: 4 additions & 0 deletions python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'')

Expand Down

0 comments on commit 4276c38

Please sign in to comment.