Close

ahhh... I need help, I don't see it

A project log for sloth badge

I guess I can't stop doing badges. Really love the @pimoroni #bearables - but they don't have sloths :(

davedarkodavedarko 12/09/2017 at 22:538 Comments

Somewhere along I had it go to sleep just fine, but it didn't wake up. Now it wakes up fine, but doesn't want to go to sleep. Seems like I don't have the millis stuff right anymore, I don't get to where the comment "// HOW DO I GET HERE?" is. Too tired to see it, gonna go to bed.

#include <avr/sleep.h>

boolean leds_on = true;

unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
const long interval = 1000;

ISR(INT0_vect) {
  sleep_disable();
  leds_on = true;
}

void setup() {
  // put your setup code here, to run once:
  PORTB |= (1 << PB1); // input
  DDRB &= ~(1<<PB1);

  shutdown_chip();
}

void loop() {
  
  
  if (leds_on)
  {
    cli();
    leds_on = false;
  }

  currentMillis = millis();
  if ( !(PINB & (1 << PB1)) )
  {
    charlie(3);
    
    if (currentMillis - previousMillis >= interval)
    {
      // HOW DO I GET HERE?
      charlie(5);
      delay(2000);
      shutdown_chip();
    }
    else
    {
      charlie(2);
    }
  }
  else
  {
    animate_leds();
    previousMillis = currentMillis;
  }
}

void shutdown_chip()
{
  leds_off();

  /* Clear WDRF in MCUSR */
  MCUSR &= ~(1 << WDRF);
  /* Write logical one to WDCE and WDE */
  /* Keep old prescaler setting to prevent unintentional time-out */
  WDTCR |= (1 << WDCE) | (1 << WDE);
  /* Turn off WDT */
  WDTCR = 0x00;

  ADCSRA &= ~(1 << ADEN); // turn off adc

  GIMSK |= (1 << INT0);
  GIMSK |= (1 << PCIE);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sei(); // Enable global interrupts
  sleep_cpu();
  sleep_disable();
}

void animate_leds()
{
  for (int i = 0; i < 12; i++) {
    charlie(i);
    delay(50);
  }
  for (int i = 0; i < 12; i++) {
    charlie(11 - i);
    delay(50);
  }
}

void leds_off()
{
  DDRB &= ~(
            (1 << PB0) |
            (1 << PB2) |
            (1 << PB3) |
            (1 << PB4)
          );
  PORTB &= ~(
             (1 << PB0) |
             (1 << PB2) |
             (1 << PB3) |
             (1 << PB4)
           );
}

void charlie (int var) {
  leds_off();

  switch (var) {
    case 0: // 1
      DDRB |= (1 << PB0) | (1 << PB2); // output
      PORTB |= (1 << PB0); // HIGH
      PORTB &= ~(1 << PB2); // LOW
      break;
    case 1: // 2
      DDRB |= (1 << PB0) | (1 << PB2); // output
      PORTB |= (1 << PB2); // HIGH
      PORTB &= ~(1 << PB0); // LOW
      break;
    case 2: // 3
      DDRB |= (1 << PB2) | (1 << PB3); // output
      PORTB |= (1 << PB2); // HIGH
      PORTB &= ~(1 << PB3); // LOW
      break;
    case 3: // 4
      DDRB |= (1 << PB2) | (1 << PB3); // output
      PORTB |= (1 << PB3); // HIGH
      PORTB &= ~(1 << PB2); // LOW
      break;
    case 4: // 5
      DDRB |= (1 << PB3) | (1 << PB4); // output
      PORTB |= (1 << PB3); // HIGH
      PORTB &= ~(1 << PB4); // LOW
      break;
    case 5: // 6
      DDRB |= (1 << PB3) | (1 << PB4); // output
      PORTB |= (1 << PB4); // HIGH
      PORTB &= ~(1 << PB3); // LOW
      break;
    case 6: // 7
      DDRB |= (1 << PB0) | (1 << PB3); // output
      PORTB |= (1 << PB0); // HIGH
      PORTB &= ~(1 << PB3); // LOW
      break;
    case 7: // 8
      DDRB |= (1 << PB0) | (1 << PB3); // output
      PORTB |= (1 << PB3); // HIGH
      PORTB &= ~(1 << PB0); // LOW
      break;
    case 8: // 9
      DDRB |= (1 << PB2) | (1 << PB4); // output
      PORTB |= (1 << PB2); // HIGH
      PORTB &= ~(1 << PB4); // LOW
      break;
    case 9: // 10
      DDRB |= (1 << PB2) | (1 << PB4); // output
      PORTB |= (1 << PB4); // HIGH
      PORTB &= ~(1 << PB2); // LOW
      break;
    case 10: // 11
      DDRB |= (1 << PB0) | (1 << PB4); // output
      PORTB |= (1 << PB0); // HIGH
      PORTB &= ~(1 << PB4); // LOW
      break;
    case 11: // 12
      DDRB |= (1 << PB0) | (1 << PB4); // output
      PORTB |= (1 << PB4); // HIGH
      PORTB &= ~(1 << PB0); // LOW
      break;
    default:
      ;
  }
}

Discussions

Frank Buss wrote 12/10/2017 at 08:34 point

The cli in your loop disables all interrupts, which are required to update the variable millis uses.

  Are you sure? yes | no

davedarko wrote 12/10/2017 at 08:35 point

but I only do cli once after wakeup? millis then get's updated in the loop

  Are you sure? yes | no

Frank Buss wrote 12/10/2017 at 17:42 point

I think "cli" is persistent when "loop" is left, so interrupts are then disabled permanently. I think the program flow was this: first you call "shutdown_chip", which enables interrupts with "sei", but in the interrupt, "leds_on" is set to true, and then "loop" is called from the Arduino framework, because the setup function is left after the chip is awake again, which then calls "cli", which is the reason why after this "millis" doesn't work anymore.

I didn't look into the details, but might be a good idea to never disable the interrupts, or just disable the external interrupt for the INT0_vect, if this is possible, or otherwise check in the interrupt handler if the loop is still running.

  Are you sure? yes | no

davedarko wrote 12/10/2017 at 11:10 point

okay, I currently fixed it with a counter and a small delay. Not the best way to do it, but it get's the job done :) first alpha version is working, nice

  Are you sure? yes | no

Jarrett wrote 12/09/2017 at 23:31 point

Is the charlie(3); line being called?

  Are you sure? yes | no

davedarko wrote 12/10/2017 at 07:18 point

yes, also the charlie(2) in the else. Sad thing is I have no debug serial port or chance to check values of the time values..

  Are you sure? yes | no

Bastiaan wrote 12/09/2017 at 23:02 point

Are you getting in the if statement above where you mention? You are checking if PB1 is low, right? Half of my comment disappeared before, hope you get it now.

  Are you sure? yes | no

davedarko wrote 12/10/2017 at 07:19 point

yup. But it seems like the time stuff is broken, only charlie 2 & 3 are being called.

  Are you sure? yes | no