"Undoing" the creation of an interrupt

My project uses this code for an interrupt:

void createInterrupt()
{
 
  cli();//disable interrupts
    ADCSRA = 0; // clear before adding bits
    ADCSRB = 0; // clear before adding bits
    ADMUX |= (1 << REFS0); //set reference voltage
    ADMUX |= (1 << ADLAR); //left align the ADC value- to read only the highest 8 bits
    ADCSRA |= (0 << ADPS0) | (1 << ADPS0) | (1 << ADPS0); //set ADC clock
    ADCSRA |= (1 << ADATE); //enabble auto trigger
    ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
    ADCSRA |= (1 << ADEN); //enable ADC
    ADCSRA |= (1 << ADSC); //start ADC measurements
    sei();//enable interrupts
}

ISR(ADC_vect)
{
  count++;
  if (count > wait)
  {
    count = 0;
    PORTD = sine[pos];
    pos += hop;
    if (pos > 99)
      pos = 0;
  }
}

However there are only certain modes that use this interrupt, and I’d like it to not be slowing things down with “time sharing” while not in use.

There are functions for turning off interrupts like cli() and noInterrupts(), but that seems too comprehensive. I don’t want to disable anything more than this one interrupt I created.

So how can I “undo” it’s creation, when it’s not being used?

You could always just disable the interrupt with the ADIE (Analog Digital converter Interrupt Enable) bit of ADCSRA.

What does this line do

ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete

Perhaps its opposite is what you want ?

…R

maybe use timer interrupt? timer0 and timer use carefully

Robin2 wrote:

What does this line do
Code: [Select]
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete

<<<< UPDATE TO THIS POST: >>>>
After some discussion, Robin2 looked up the correct answer to the above question in the manual, and reported below in post #10:

ADCSRA |= (1 << ADIE);
will cause an interrupt to happen when an analog reading completes
Conversely
ADCSRA &= (0 << ADIE);
should stop that happening

So my answer below is a little wrong, but I must leave it to keep the logic of this thread intact.

And it now seems I need a small correction to the above correction: GoForSmoke in comment #14 below states that
ADCSRA &= (0 << ADIE);
won’t work and should have been
ADCSRA &= !(1 << ADIE);
“Because 0 left shifted … is still 0.”

But then starting in post #15, people start pointing out that the line above is also wrong and won’t work, because it uses the “!” (logical not) instead of “~” (ones complement) to reverse the bit. Meaning the line should have been:
ADCSRA &= ~(1 << ADIE);
or
ADCSRA &= ~ bit (ADIE); // for clearity
or even
bitClear (ADCSRA, ADIE); // which makes the most sense to me.

A related fact I discovered experimentally after writing these posts, is that you cannot use
analogRead() when the analog pins have been setup to work directly with interrupts as in the above. If you do, execution of your loop() will hang on the analogRead() line, even though the interrupts will continue working just fine.

<<<< END OF UPDATE TO THIS POST >>>>


True, Robin2:
I didn’t show it’s use here; but, in another mode of the full sketch, the analog value of pin A0 is read repeatedly within the interrupt by the following line:

buffA[buffCnt]=ADCH;

The line you asked about tells the Analog-to-Digital converter to discard the current value and take a new mesurement, to be ready for the next interrupt. And, letting the interrupt read the analog pin directly is much faster than would be repeatedly calling the line:

buffA[buffCnt] = analogRead(A0);

a line which doesn’t even begin to do an A/D conversion until called, making the interrupt take longer to complete.

Posted by DrAzzy:

You could always just disable the interrupt with the ADIE (Analog Digital converter Interrupt Enable) bit of ADCSRA.

I think that’s the answer DrAzzy. That should prevent time wasted by A/D conversion as well. Thanks.

What is

    ADCSRA |= (0 << ADPS0) | (1 << ADPS0) | (1 << ADPS0); //set ADC clock

supposed to do?

0 << ADPS0 is all bits zero == 0

OR that with 1 << ADPS0 and you have some value that you could just |= ADCRSA with

but instead you OR with the same 1 << ADPS0 again first!

Sooooo, ummmm, why? I can’t figure it out! I would just

    ADCSRA |= (1 << ADPS0); //set ADC clock

because that should be the same ADCSRA bit set.

Hahaha! Mentally picturing your confusion DID make me laugh. :slight_smile:

Your theory is logical; but for some reason,

ADCSRA |= (1 << ADPS1); //set ADC clock

gave me 233,000 Hz, the same as did the line,

ADCSRA |= (1 << ADPS0); //set ADC clock

It took using both together:

ADCSRA |= (1 << ADPS0) | (1 << ADPS1); //set ADC clock

to get the desired frequency.

I should test those posibilites again so see if I made another mistake.
The “(0 << ADPS0)” above was a typo. Should have been (1 << ADPS0)

And regarding your question about why the repeated OR value:
There are three possible values to include. Using all three would make the line:

ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2); //set ADC clock

I only needed two of them, but made the third value a repeat to give me a visual place-holder for for my own eyes, thinking ahead about times I will use it.

Yes, it makes sense when you use different values and fix the typo because then it says do a completely different thing.

If I had seen your newer code, the fixes would have been noted.

CosmickGold:
Robin2 wrote:

What does this line do

Code: [Select]
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete



The line you asked about tells the Analog-to-Digital converter to discard the current value and take a new mesurement, to be ready for the next interrupt.

That is not what your comment says.

Perhaps foolishly I assumed the comment was correct.

On the other hand, if the comment is correct (and I think it is) then I think my suggestion is correct. Perhaps it is time for you to RTFM

…R

If I've made a mistake, I want to go back and correct it in the comment where I made it; because I very much DON'T want to mislead anyone. Electronics is hard enough to understand without being given erroneous information.

However, I don't see the conflict you point out about the two comments. They seem both part of the same process to me. My understanding is that "//enable interrupts when measurement complete" (the first comment) means that the value was held steady while being read, but after that the line you questioned allows the "converter to discard the current value and take a new measurement" (the second comment) by turning interrupts on again.

Perhaps it is time for you to RTFM

I'm not good at "RTFM". I wish I was, but I had to be tutored an hour after school each day in the first grade, in order to learn to read at all. The surgeon who brought me into this world, squeezed the forceps too hard when he pulled me out by the head, smashing them through my skull, which destroyed a part of the back of my brain that normally interprets vision. I'm lucky to even be alive after that!

(At least I'm able to learn, just not much by "RTFM".)

I sympathize with people who have difficulty with manuals, but IMHO it is pretty much unavoidable if you want to use the sort of code you are trying to use. Programming requires the detailed precision that is only available in the manual.

From my reading of the manual

ADCSRA |= (1 << ADIE);

will cause an interrupt to happen when an analog reading completes

Conversely

ADCSRA &= (0 << ADIE);

should stop that happening

I hope I have the code correct - I find that way of describing bit values confusing. I much prefer to figure out the bit positions in binary - eg 0b00100100 (this example means nothing)

…R

much prefer to figure out the bit positions in binary

So, use bitSet(), with ADCSRA as the value to set the bit in, and ADIE as the bit to set.

PaulS:
So, use bitSet(), with ADCSRA as the value to set the bit in, and ADIE as the bit to set.

NO .... small tantrum :slight_smile:

...R

CosmickGold:
There are functions for turning off interrupts like cli() and noInterrupts(), but that seems too comprehensive. I don’t want to disable anything more than this one interrupt I created.

So how can I “undo” it’s creation, when it’s not being used?

Its not created at runtime, its in the code, its there till you program another sketch.

Use the appropriate interrupt enable bit, all interrupts have a bit to enable them individually.
In fact you don’t need the cli() sei() in your setup, just disable the ADC interrupt first,
then disable the ADC, then reprogram the registers, re-enable interrupts and finally
trigger it to convert.

Be careful to read the full details of interrupt hardware when using them - its pretty normal
for the ISR to have to probe a register to re-enable the same interrupt (ie there is a handshake
between the hardware and the code of the ISR)

Another way to control interrupt routines is to guard them with a boolean:

volatile bool adc_enable = false ;

ISR ADC_vect ()
{
  if (!adc_enable)
    return ;
  ... other stuff
}

Easy to switch the routine on and off and a stub ISR like this only take a couple of microseconds
if the guard is false.

Robin2:
NO … small tantrum :slight_smile:

…R

What is

ADCSRA &= (0 << ADIE);

supposed to do?

Because 0 left shifted till the moon falls is still 0.

So why not

ADCSRA &= 0;

instead except that I bet you only wanted to mask the ADIE bit of ASCSRA?

ADCSRA &= !(1 << ADIE);

should do that.

GoForSmoke:
ADCSRA &= !(1 << ADIE);

This should work better:

ADCSRA &= ~(1 << ADIE);

GoForSmoke:
What is

ADCSRA &= (0 << ADIE);

supposed to do?

Because 0 left shifted till the moon falls is still 0.

As far as I know it puts a 0 in the ADIE bit position whereas

So why not

ADCSRA &= 0;

would set all the bits in the register to zero.

Which is exactly why I prefer to RTFM and figure out all the required bit values in the form 0b010101011 or whatever

…R

I agree

Robin2:
As far as I know it puts a 0 in the ADIE bit position

As well as every other position…

ADCSRA &=(0<<ADIE) is equivilent to ADCSRA=0, as anything bitwise anded with 0 is 0.

If you’re suggesting that I didn’t RTFM on bits, you’re not interpreting my post for meaning.
I learned bit math in school starting over 50 years ago.

christop’s right, ~ for invert bits not !

I manually typed the program in so here’s TFM,

void setup() {
  Serial.begin( 115200 );

  byte i, j;

  j = 0b10101011; // or whatever
  Serial.println( "How to not clear just one bit, then how to." );
  Serial.print( "Sample value to clear bits in 0b" );
  Serial.println( j, BIN );
  Serial.println( );

  for ( i = 0; i < 8; i++ )
  {
    Serial.print( (0 << i) );
    Serial.print( " - " );
    Serial.print( j & (0 << i) );
    Serial.print( " - 0b" );
    Serial.println( j & ~(1 << i), BIN );
  }
}

void loop() { }

How to not clear just one bit, then how to.
Sample value to clear bits in 0b10101011

0 - 0 - 10101010
0 - 0 - 10101001
0 - 0 - 10101011
0 - 0 - 10100011
0 - 0 - 10101011
0 - 0 - 10001011
0 - 0 - 10101011
0 - 0 - 101011

christop:
This should work better:

ADCSRA &= ~(1 << ADIE);

christop is right. That is the only way of doing it.

Or more readably:

ADCSRA &= ~ bit (ADIE);

Or even:

bitClear (ADCSRA, ADIE);