Leaving interrupt on ATTiny

Go To Last Post
30 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello!

 

It seems I am not leaving the interrupt properly, or shall I say entering the program back again from sleep mode.

 

I am putting tiny to sleep after few seconds, if nothing happens, this works. When sensor is triggered, via interrupt pin, the tiny is worked up, works, however, I am not happy how it works. For example, at the end of the ISR I have hardcoded certain variables, to put the program into that state, all good, but it seems the variable setting just does not work well with my program, where I have left it off , when going to sleep...

 

So, my question is how to leave the ISR and go to the start of the loop of the program, with clean slate? Something what happens when the whole setup is powered, turned on?

 

indeed, I would like to get rid of the variables setting that I am using at the moment...

 

Is it possible to use the "goto" or "rune the setup()" or something similar ?

 

Best.

 

 

Bravo!!!

Last Edited: Wed. Jul 24, 2019 - 12:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mu234 wrote:
Is it possible to use the "goto" or "rune the setup()" or something similar ?
If you are even contemplating that you have not designed your program clearly. A sleeping program generally has the structure:

int main(void) {
    hw_init();
    sleep_init();
    while (1) {
        awake_code();
        setup_waking_ISR_trigger();
        sleep()
    }
}

EMPTY_ISR(some_vect);

After all the initial setup it does the "awake code", then it prepares and actually does go to sleep. Some time later the wakeup even occurs. That triggers the attached interrupt. I have shown EMPTY_ISR() to emphasise the point that the interrupt itself does not actually need (and often will not) do anything but that ISR() ends in a RETI and the place it RETIs to is the instruction after the SLEEP opcode. That might often simply be the RJMP at the end of the main while() loop that takes it back round to do everything all over again. so a bit more awake_code then prepare to and do sleep again and so on.

 

If there multiple things to be done after wakeup you could use some combination of:

int main(void) {
    hw_init();
    sleep_init();
    while (1) {
        awake_code();
        setup_waking_ISR_trigger();
        sleep()
        stuff2_when_awakened();
    }
}

ISR(some_vect) {
    stuff1_when_awakened();
}

Perhaps with stuff1/stuff2 replacing "awake_code()" completely. The suff(1) in the ISR is obviously done most immediately then the stuff(2) is done when that returns from the ISR back to the loop after the SLEEP.

 

How does your implementation deviate from this pattern? Why can't you just use the normal ISR RETI to get you back into the loop at the point just beyond sleep() ?

 

PS forgot to say that without seeing your code it's only possible to talk in generalisations but you should have a clear picture in your heard as to what the path of execution will be. Anything requiring a "goto"/jump from one piece of code to another almost always suggests the code has not been designed with path of execution in mind. GOTO is a hangover form the 60's / 70's when more elegant code structures were not available.

Last Edited: Wed. Jul 24, 2019 - 12:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please take a look at this thread, and specifically this app note:

 

Interrupt System in tinyAVR 0- and 1-series, and megaAVR 0-series

 

via:

http://ww1.microchip.com/downloa...

 

EDIT: link

Last Edited: Wed. Jul 24, 2019 - 01:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moe123 wrote:
Interrupt System in tinyAVR 0- and 1-series, and megaAVR 0-series
What leads you to think it's AVR-0/1 he's talking about. So far I only see "Tiny". The vast majority of them (at least up to now) are not Xtiny ;-)

 

One of his previous threads:  https://www.avrfreaks.net/forum/how-programm-tiny-once-bolded-board  strongly suggests it could be t25/45/85 in fact.

Last Edited: Wed. Jul 24, 2019 - 01:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are right, maybe its not ;-)...maybe something else, however the appnote gives a very nice explanation for startes on how "in general" the interrupt controller works:

 

Static Priority interrupts, Round-Robin...High priority interrupt vector. so maybe the OP would like to take a look :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moe123 wrote:
Static Priority interrupts, Round-Robin...High priority interrupt vector. so maybe the OP would like to take a look
None of which is relevant for the vast majority of traditional AVR. That's all about "X" architecture which, until these new Xtiny, never seemed to really take off in the way tiny/mega did over the last 20 years.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed, I am working with AtTiny45 .

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, very useful input. Before I dig into details, where would you put the RETI, within ISR?

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

ISR(some_vect) {
    stuff1_when_awakened();
}

mu234 wrote:
Before I dig into details, where would you put the RETI, within ISR?

 

In C, it's done for you, so not needed.

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
In C, it's done for you, so not needed.

Indeed. Usually in C if you write:

void function(void) {
    //stuff
}

this creates:

function:
 ;stuff
 RET

so the clocing } of a C function is, by implication, a "RET". But when you use:

ISR(some_vect) {
    // stuff
}

this first breaks down (translating "some_vect" into something like __vector_07) to be something like:

__attribute__((signal)) void __vector_07(void) {
    // stuff
}

then when this is compiled the "signal" attribute applied to it when using "ISR()" causes the compiler to recognise this as an interrupt handler so it (simplistically) generates:

__vector_07:
    PUSH R1
    CLR R1
    ; stuff
    POP R1
    RETI

this time the "}" at the end of the code has generated RETI at the end. That not only returns but, as it does so, it re- enables the global interrupt flag in the SREG. More to the point, Back in main() the code:

while(1) {
    awake();
    sleep();
}

will have been compiled as:

loop:
    CALL awake
    SLEEP
    RJMP loop

this will have stopped at the SLEEP (cos that is what SLEEP does!) so when the awakening interrupt occurs the address of the next opcode (RJMP) will be pushed onto the stack. When the ISR() hits the RETI then the place it RET(I)urns to is the stacked location (the RJMP) so it comes out of sleep, does the code in the ISR and when that is over it comes back to the next thing after SLEEP. (and in this case then loops back to "loop:" to do the whole thing all over again).

Last Edited: Wed. Jul 24, 2019 - 04:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello to all of you,

thank you for all inputs, will have to go over each. Anyway, here are the blocks, how program is organized at the moment. Indeed, if you would like to see the code, let me know and will post it...

Mainl loop{

1) “state machine” ( here the sensor threshold timing is measured )

2) “ making a decision according to the measurements

3) make action according to decision , if certain action is found go to sleep, woken by interrupt that is set in setup(), namely isr

4) wdt reset

} //end of main loop

Again all this code works, however, I need to find a more simple, robust way of handling ifs, there is plenty of them in 3) action block, apparently I am not considering all of the possibilities...

So, the question, I am not explicitly using either reti or rjmp in isr, do I need to? And, will interrupt put me back to where the uC went to sleep or at the start of the main loop?

Best.

Bravo!!!

Last Edited: Thu. Jul 25, 2019 - 03:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mu234 wrote:
I am not explicitly using either reti or rjmp in isr, do I need to?
Your are over thinking this. An ISR is just a C function. Forget RET, forget RETI. The C compiler handles all that stuff for you.

 

More important is the structure and execution sequence you are looking for.

 

Generally the rule is that you put the slow, mundane stuff in a repetitive loop in main() and anything that needs "fast service" into interrupts. When the event occur, the ISR()s quickly handle things then let the mundane loop continue plodding along as if nothing happened.

 

The only "issue" is when you need to synchronize things between what happens in the ISR()s and what happens in main()

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,

 

went thru the whole program and indeed, when I hard code the variables in the ISR, certain variables are overridden, therefore, I am wondering, if the variables keep the values once the uC goes to sleep? And, can I have a more complicated operation in ISR than just defining bools (true and false)? For instance, would ISR hand a simple if(), etc? Actually, how much programming can be done in ISR?

 

Another question, why does the uC produces certain buzzing noice, hardly audible when I am putting uC to sleep, not all of them :/ interesting, but confusing...

 

Best.

 

 

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mu234 wrote:

 

 

Another question, why does the uC produces certain buzzing noice, hardly audible when I am putting uC to sleep, not all of them :/ interesting, but confusing...

 

Best.

 

 

 

For the first part, i think Clawson would help you better. for the part of the noise, although in general the MCU goes to sleep (if you are programming it right), but there is always some sort of power consumption, this differs on which HW you are putting to sleep, which pins are just left floating, how close your decoupling capacitors (e.g. 100nF) from the MCU and how good is your ground plane in the PCB. another thing for the ground noise is the wires/traces you are using to measure your power consumption (connected to the Osci).

 

Regards,

Moe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, when you say “programming right”, it works, even the energy consumption looks good, according to plan... was thinking to put all the ports during sleep mode in high Z and put them back when awaken, in ISR. From perspective of buzzing this could be a solution, but how to do that? In addition, why is this occurring only on some modules and not only on all of them, the layout, etc. is the same... I guess this is definitely a question of software?

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since we dont have any code, we can only guess...maybe its software, maybe its HW issue or both.

 

Regards,

Moe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, let me post the code, which part do you need?

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

 

 

The only "issue" is when you need to synchronize things between what happens in the ISR()s and what happens in main()

 

would be nice to see this part

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed, I most certain I have the issue in synchronization :( thanks god it can be solved due to the fact it is only about bool variables :) I guess.

So, again, what could would you like me to post with regard to imterrupt code, probably best would be isr, gotosleep code and how it is awaken?

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

decoupling c is 3-4 cm away (22uF),
during the time (aprox 500ms) when tiny is on the way to sleep, the led is lid, so, indeed, this time the power consumption may be to big for the regulator, maybe this is the noise I am hearing... will reduce the pwm of led to 10%, to check, if this is the factor :)
More follows,
Best.

Bravo!!!

Last Edited: Mon. Jul 29, 2019 - 04:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mu234 wrote:
was thinking to put all the ports during sleep mode in high Z and put them back when awaken, in ISR.

BAD idea, high z means ports are inputs, floating inputs result in high current as pins float back and forth across logic treashold!

 

mu234 wrote:
decoupling c is 3-4 cm away (22uF),

22uF is NOT a decoupling cap, it is bulk storage, decoupling is more like a 100nF placed as close to the VCC pin(s) as possible.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To make something clear this is ceramic cap, while there is also tantalum... but anyway, you are right the inputs should not be hi z, other way around.

More follows.

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
//ISR
ISR (PCINT0_vect)
{
  sleep_disable();
  ////  // set pins to original setup
  //    pinMode(7, LOW);
  //    pinMode(6, LOW);
  //    pinMode(5, LOW);
  //    pinMode(3, LOW);

  power_all_enable();    // power everything back on

  // also "wake up" enable the wdt
  wdt_enable(WDTO_2S);

  // *** state machine for measuring time of sensor level ***
  if (Sensor.getProximity() > HT) {
    currentState = WAITING_BELOW;
  }
  else {
    currentState = WAITING_ABOVE;
  }
  // *** end of state machine for measuring time of sensor level ***

  //end of interrupt output 

  // the wanted state after we wake up with interrupt
  //  1-0-0-1
  ledState = true;
  //  fading = false;
  //  fadeUp = true;

  //new
  aboveHT = 0;
  belowHT = 0;

  // end of interrupt output 

} //end of ISR
//going to sleep rutine
void goingToSleep() {

  //when led is off and brightness is 0
  // - turn on the signal led
  // - start counting towards sleep

  // turn ON led sig
  analogWrite(ledSigPin, 255);

  if (!ledState && !ledState1 && (brightness == 0) ) {
    // increase my counter
    sleepCounter++;
    // check my counter and make a decision
    if (sleepCounter >= 500) {
      //go to sleep!
      goToSleep();
      //analogWrite(ledSigPin, 120);
    }
  }
  //otherwise:
  // - turn off sinal led
  // - and reset the counter to 0
  else {
    //analogWrite(ledSigPin, 0);
    sleepCounter = 0;
  }
}
void goToSleep()
{
  // turn off the led sig
  analogWrite(ledSigPin, 0);

  //  //set pins to HighZ
  //    pinMode(7, INPUT);
  //    pinMode(6, INPUT);
  //    pinMode(5, INPUT);
  //    pinMode(3, HIGH);

  Sensor.clearInterrupt(); //this will clear sensor interrupts!
  Sensor.setProximityContinuous(true); // read prox while sleeping

  // disable wdt while sleeping
  wdt_disable();

  // turin off setting while sleeping
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  sleep_enable();
  sleep_cpu();
}  // end of goToSleep
void loop() { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  OS = Sensor.getProximity();

  currentTime = millis();

  switch (currentState) {
    case WAITING_ABOVE:
      if (OS > HT) {
        belowHT = 0;
        belowHT += currentTime - startTime;
        startTime = currentTime;
        currentState = WAITING_BELOW;
      }
      break;
    case WAITING_BELOW:
      if (OS < HT) {
        aboveHT = 0;
        aboveHT += currentTime - startTime;
        startTime = currentTime;
        //        // when proximity drops below HT then we toggle the fadeUp
        //        fadeUp = !fadeUp;

        //in fading toggle fadeUp
        if (fading) {
          fadeUp = !fadeUp;
        }
        currentState = WAITING_ABOVE;
      }
      break;
  }

  ledAction();

  //we have reached the end of program, reset the WDT
  wdt_reset();

} // +++++++++++++++++++++++++++++++++++++++++++++++++end of main loop++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

 

// set the led
void ledAction() {

  //led off #1
  // 0-0-0-1
  if(!ledState && !ledState1 && !fading && (fadeUp or !fadeUp) ){
    myFadeOut();

    //turn on the led sig
    //analogWrite(ledSigPin, 255);

    //going to sleep
    goingToSleep();
  }

  //led on 5
  // 1-0-0-1
  else if(ledState && !ledState1 && !fading && fadeUp){
    brightness = 50;
    analogWrite(ledPin, pgm_read_byte(&table[brightness]));

    fadeUp = true;
    fading = false;
  }
  //led on 10
  // 1-1-0-1
  else if(ledState && ledState1 && !fading && fadeUp){
    brightness = 255;
    analogWrite(ledPin, pgm_read_byte(&table[brightness]));

    fadeUp = false;
    fading = false;
  }

}

 

Just to let you know, definitely I have a problem due to the "interrupt" or synchronisation as pointed out by other, for example, I have tried the code without going to sleep/awake and it works perfectly.

 

Another thin the buzzing is related to the led which is lid while counting towards sleep... because, if I set the pwm of that led to less eg. 10% , the buzzing is lower... in addition, if the led is turned off earlier then there is no buzzing... 

 

ok, the buzzing seems  to be sorted, so far I have found out the, if the led is not well soldered I get the buzzing, which is not the case on the other module, however, it could as well be the led as a component is not good...

 

Anyway, I have posted the code, have fun and I am looking forward to your comments!

 

Best.

Bravo!!!

Last Edited: Tue. Jul 30, 2019 - 11:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are sharing a variable between main and an interrupt handler, you need to declare it "volatile".  Are you doing that?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for pointing this out, I was not sure, if this was important, however, indeed, all variables that are in the isr are volatile...

Finally, I have made it to work! The main problem was that some of vars where not properly defined in the logic.

Anyway, if any of you thinks that the structure could be handled better, in the right way, etc - improvements. I am looking forward to your comments, suggestions!

Best.

Bravo!!!

Last Edited: Tue. Jul 30, 2019 - 02:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mu234 wrote:
was that some of vars where not properly defined in the logic.
Curious to know what that means?

 

As for this kind of thing and the "structure" - you should be catching all this in the design phase before you even write a line of C/C++. A well designed program should have a clear (and faultless) implementation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are right but sometimes the creative process does not work that way, at least with me, I go forward and code on fly, hence the errors, when it does not work I look back, correct, draw blocks, etc. I know, this is bad habit, but this is how it works for me ...

With regard to the “defined in the logic”, in this case 4 bools are used and the core of the program is changing this vars either true or false, you can imagine how many states is there (2 on power of 4) ... gets complicated doing it by hearth... so, if you missed a particular one you are fried, it does not work,

Anyway, I would be more than happy to hear other ways of dealing with such a logic, was thinking to use functions such as or, xor, etc., but somehow was not comfortable. I guess there are other ways to deal with that?

Best.

PS there is still something open, how to change the ports out/input or pull-up, etc. anybody knows the code?

Bravo!!!

Last Edited: Tue. Jul 30, 2019 - 05:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

4 bools = 1 enum (with 16 states)
.
As I say this is the kind of thing to think through upfront.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very good, did not know this could be a solution, good to know enum!

Thanks! Will have a look...

Best.

Bravo!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all, 

 

I have managed to put the tiny to sleep and the consumption seems fairly alright (around 530uA) 

...

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA = 0;            // turn off ADC)

...

 

All good, the application works in all cases, but I am wondering why in some cases (the same software and product, but different module) the consumption during sleep fluctuates... Indeed, I am looking at uA therefore hardly the case, but I am wondering why in certain cases that consumption is steady, while in others it fluctuates between 500uA and 600uA...

 

Anyone? 

 

Best.

Bravo!!!