New ATtiny's and ISR Troubles

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

Hey all,

 

I'm having trouble with a variable modified in the ISR but not being updated in the main code. A couple comments:

 

- My variable is volatile

- My ISR is being called (in the code below, if the LED toggling is moved to the ISR it works just fine)

- I don't think I have any other interrupts enabled, so I don't think the whole unit is resetting as I saw suggested in another thread

- I've actually got the code working on an ATmega328p, but "translated" for an ATtiny1616 it doesn't work

 

Here's the code I'm having trouble with. I've got a button that connects ground to PC1 that triggers the ISR and an LED wired to PC0 that I am trying to toggle by modifying the global volatile x.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile char x;

const uint8_t led_pin = 0; // PORT C
const uint8_t btn_pin = 1; // PORT C

int main() {
  // LED setup
  PORTC.DIR |= (1 << led_pin); // Set LED pin to output

  // Button setup
  PORTC.DIR &= ~(1 << btn_pin); // Set button as input
  PORTC.PIN1CTRL |= (1 << 3); // Enable pull-up resistor

  // Set interrupt on falling edges
  PORTC.PIN1CTRL |= (1 << 0);
  PORTC.PIN1CTRL |= (1 << 1);

  sei(); // Set global interrupts 

  while(1){
    if (x == 1){
      PORTC.OUT ^= (1 << led_pin); // toggle led
      _delay_ms(500); // debounce
      x = 0; // unset x
    }
  }
}

ISR(PORTC_PORT_vect) {
  x = 1; // set x
  PORTC.INTFLAGS |= (1 << 1); // Clear interrupt flag
}

For comparison, here's my working code for the ATmega328p that does the same thing:

#include <avr/io.h> // for pin and address functions
#include <avr/interrupt.h> // for interrupt related commands
#include <util/delay.h>

volatile char x;

const uint8_t led_pin = PD5; // This is digital pin 5
const uint8_t btn_pin = PD2; // This is the INT0 external interrupt pin

int main() {
  // LED setup
  DDRD |= (1 << led_pin); // Set LED pin to output

  // Button setup
  DDRD &= ~(1 << btn_pin); // Set button as input
  PORTD |= (1 << btn_pin); // Enable pull-up resistor

  // Set INT0 interrupt behaviour: Interrupt on falling edges
  EICRA |= (1 << ISC01);
  EICRA &= ~(1 << ISC00);

  sei(); // Set global interrupts 
  EIMSK |= (1 << INT0); // Set INT0 interrupts

  while(1){
    if (x == 1){
      PORTD ^= (1 << led_pin); // Set LED pin to high
      _delay_ms(500);
      x = 0;
    }
  }
}

ISR(INT0_vect){
  x = 1; // set x
}

Any ideas guys? I'm using El Tangas' jtag2updi programmer, avr-gcc 8.2.0, and avrdude 6.3. Thanks for taking the time to read this!

 

Cheers,

S

This topic has a solution.
Last Edited: Sat. Jan 5, 2019 - 08:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ran your program as is on a T817 and it worked.

 

Needs #define F_CPU, otherwise the delay is a little long.

 

You method of debug doesn't stop the interrupt from firing several times.

 

is your button wired correctly?

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

sherazz wrote:

- My ISR is being called (in the code below, if the LED toggling is moved to the ISR it works just fine)

My first thought is the ISR is being called repeatedly so never returns to main. You can test this by putting a cli(); at the end of the ISR. This should result in a return to main and the LED going on.

If this is the case, you will have to figure why - I can't see a reason.

When you say 'toggle' do you mean 'turn on'? The way I read the data sheet writing a 1 to OUT just turns the LED on and the code doesn't then turn it off. Writing 1 to OUTTGL would toggle it.

[edit] I missed you are using exclusive OR - it should toggle [/edit]

[edit] I realised later that the cli() won't work because the ISR will do a RETI and reenable interrupts anyway. You would need to turn off the likely cause of the interrupt. I think that would be:

EIMSK &= -(1 << INT0); // Clear INT0 interrupts

[/edit]

Last Edited: Wed. Jan 2, 2019 - 06:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With your style of coding is't very easy to make a mistake. Have a look on this:

  // Set interrupt on falling edges
  PORTC.PIN1CTRL |= (1 << 0);
  PORTC.PIN1CTRL |= (1 << 1);

Why on Earth you need two operations to set one parameter? Why do you use |= instead of =?. You should type something like this:

PORTC.PIN1CTRL = PORT_ISC_FALLING_gc;

This way you clearly see what the code is doing - you just want to execute an interrupt with falling edge, no matter what previous configuration was, if any.

 

With new AVR you can try this

PORTA.DIRSET = PIN1_bm;
PORTA.DIRCLR = PIN2_bm;
PORTA.OUTSET = PIN3_bm;
PORTA.OUTCLR = PIN4_bm;
PORTA.OUTTGL = PIN5_bm;

instead of REGISTER |= (1 << blablabla):

 

extronic.pl

Last Edited: Wed. Jan 2, 2019 - 08:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey all,

 

Thanks for the helpful comments, and sorry I'm late getting back to you all.

 

@extronic: Thanks for the formatting advice! I'm pretty new to all this stuff, so I've been copying the formatting styles I've been seeing in blog posts and tutorials. So I was under the impression that this:

PORTC.PIN1CTRL = PORT_ISC_FALLING_gc;

would unset the pull up resistor (bit 3 of PINnCTRL), but doing a similar

PORTC.PIN1CTRL = PORT_PULLUPEN_bm;

would unset the ISC. Don't I have to use "REGISTER |= Something;" in this case?

 

@ajcashin: I tried cutting off the ISR like you suggested. I couldn't find an EIMSK register for the ATtiny (am I just being stupid?), but I figured I might be able to cut it off by disabling the ISC for that pin in the ISR. Unfortunately, that didn't seem to help. Like you suggested, cli() didn't work either. Thanks again for the suggestion though!

 

@jstampfl: Thanks for trying it out for me! And it's really helpful to know it's working on someone else's setup. First of all, sorry about the F_CPU, I've got that defined in my Makefile. Also, you were right about the bad debouncing, so I moved the delay to within the ISR, right before clearing the interrupt flag. This fixes the debouncing for when I toggle the LED in the ISR, but it doesn't fix the non-updating volatile. I also don't think it's a button wiring issue since my LED acts as expected when I toggle the LED in ISR.

 

Would you mind if I asked how you are programming your ATtiny? Or maybe the difference is in the compilation?

 

Also, I came across this thread shortly after my initial post (https://www.avrfreaks.net/forum/...) where someone had a similar problem on an ATmega128 because of the M103C compatibility fuse. That being said, I can't seem to find a comparable fuse on the ATtiny.

 

In any case, thanks again for all your help guys!

S

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

You can join multiple parameters this way. I like to write many comments because after few months I don't remember how my code works. Note that you can easily comment out something - in this example I commented out pull-up instead of removing this line. This let's me know that there's a not enabled feature. It's quite helpful with more advanced peripherals.

 

Attachment(s): 

extronic.pl

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

Oh, that makes a lot of sense! Thanks extronic!

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

sherazz wrote:

@ajcashin: I tried cutting off the ISR like you suggested. I couldn't find an EIMSK register for the ATtiny (am I just being stupid?), but I figured I might be able to cut it off by disabling the ISC for that pin in the ISR. Unfortunately, that didn't seem to help. Like you suggested, cli() didn't work either. Thanks again for the suggestion though!

My bad. I was looking at the wrong program. Try

PORTC.PIN1CTRL=0

Which will disable interrupt for the pin (and all your other settings, but this is debugging). It will determine if the program is looping in the ISR. If that doesn't work I would try making x a uint8_t - see if it is a compiler problem.

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

"Would you mind if I asked how you are programming your ATtiny? Or maybe the difference is in the compilation?"

 

I just used your example with no changes.

 

Used a default "New Project" in AS7

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

Hey again,

 

@ajcashin: Just tried clearing the PIN1CTRL register in the ISR. It did stop the ISR from being called multiple times (again checked by moving the LED toggling to the ISR), but still no luck with the non-updating volatile issue. I also tried switching x to uint8_t, but no luck there either. I'm also wondering if it's a compiler issue, but I'm afraid I don't know where to begin on what to change about how I call avr-gcc. Thanks again for the reply!

 

@jstampfl: Sorry for the confusion, I meant to ask whether  you were using the jtag2updi programmer, or something more like the STK600's UPDI mode. And thanks for the info! I'll see if I can get on a windows computer and try uploading the code using AS7 and report back.

 

Thanks again for all the help guys!

S

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

I am using an ATtiny817Xplained mini board.  Has built-in debugger.

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

One last thought. In main before the while loop, initialise x [i.e. just x=0; ]. If that doesn't work, maybe time for the big guns. If you can put the .lss file somewhere we can look at it, we can see the assembler output. Then we can see if the compiler has optimised something it shouldn't.

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

The code works when compiled on AS7 for me too! Thanks for all the help guys!

 

Unfortunately, I don't have ready access to a windows machine, so I hope you'll bear with me as I try and figure out how to get avr-gcc working as well.

 

So here are some more comments:

 

- the AS7.lss file was compiled in AS7 and works as intended, but was uploaded using the jtag2updi programmer

- the avr-gcc.lss file was compiled in avr-gcc but uploaded the same way, so we can rule out the programmer as the problem

- sure enough, the AS7.lss file has almost 30 more lines of code and I can't even seem to find the ISR in the avr-gcc code (though, I really don't know what I'm looking at in assembly files)

- does this suggest that avr-gcc is just optimizing out my entire ISR? Is there an obvious way to tweak optimization?

 

Finally, here is the source file used to generate both. Hopefully the formatting is a little better now.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t x;

const uint8_t led_pin = PIN0_bm; // PORT C
const uint8_t btn_pin = PIN1_bm; // PORT C

int main() {
  // LED setup
  PORTC.DIRSET = led_pin; // Set LED pin to output

  // Button setup
  PORTC.DIRCLR = btn_pin; // Set button as input
  PORTC.PIN1CTRL = PORT_ISC_FALLING_gc | PORT_PULLUPEN_bm; // Enable pull-up resistor

  sei(); // Set global interrupts

  while(1){
    if (x == 1){
      PORTC.OUTTGL = led_pin; // toggle led
      x = 0; // unset x
    }
  }
}

ISR(PORTC_PORT_vect) {
  x = 1; // set x
  _delay_ms(1000); // debounce
  PORTC.INTFLAGS |= btn_pin; // Clear interrupt flag
}

 

Thanks again for all the help so far guys!

S

 

(ps, had to rename the files to .txt to upload, sorry for the confusion!)

Attachment(s): 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

- sure enough, the AS7.lss file has almost 30 more lines of code and I can't even seem to find the ISR in the avr-gcc code

- does this suggest that avr-gcc is just optimizing out my entire ISR? Is there an obvious way to tweak optimization?

It's there...  Not as well symbol-fied as the AS7 version.   Here it is, annotated a bit...

 

000000a6 <__vector_5>:

;;; new compiler omits unnecessary save of R1/R0.  Yeah!
  a6:    2f 93           push    r18
  a8:    2f b7           in    r18, 0x3f    ; 63
  aa:    2f 93           push    r18
  ac:    8f 93           push    r24
  ae:    9f 93           push    r25
  b0:    ef 93           push    r30
  b2:    ff 93           push    r31
  b4:    81 e0           ldi    r24, 0x01    ; 1   ;;; this is supposed to be "x = 1"
  b6:    80 93 02 01     sts    0x0102, r24    ; 0x800102 <__bss_end+0x9f>

  ba:    2a e2           ldi    r18, 0x2A    ; 42   ;;; delay_ms
  bc:    8c e2           ldi    r24, 0x2C    ; 44
  be:    9a e0           ldi    r25, 0x0A    ; 10
  c0:    21 50           subi    r18, 0x01    ; 1
  c2:    80 40           sbci    r24, 0x00    ; 0
  c4:    90 40           sbci    r25, 0x00    ; 0
  c6:    e1 f7           brne    .-8          ; 0xc0 <__vector_5+0x1a>
  c8:    00 00           nop
  ca:    e0 e4           ldi    r30, 0x40    ; 64  ;;;reset INTFLAGS
  cc:    f4 e0           ldi    r31, 0x04    ; 4
  ce:    81 85           ldd    r24, Z+9    ; 0x09
  d0:    82 60           ori    r24, 0x02    ; 2
  d2:    81 87           std    Z+9, r24    ; 0x09
  d4:    ff 91           pop    r31   ;;; restore context and return.
  d6:    ef 91           pop    r30
  d8:    9f 91           pop    r25
  da:    8f 91           pop    r24
  dc:    2f 91           pop    r18
  de:    2f bf           out    0x3f, r18    ; 63
  e0:    2f 91           pop    r18
  e2:    18 95           reti

 

Note the part that I highlighted in red.  It loads 1 into a register and then stores that at memory location 0x102, where it thinks "x" is located.  However, the tiny1616 does NOT HAVE RAM at 0x100 - according to the iotn1616.h (from Atmel.ATtiny_DFP.1.2.118), RAM starts at 0x3800.

And in fact in the AS7 build, the similar lines in the ISR read:

  dc:	81 e0       	ldi	r24, 0x01	; 1
  de:	80 93 00 38 	sts	0x3800, r24	; 0x803800 <_edata>

 

So my guess is that somehow your install of avr-gcc does not have correct iotn1616.h and/or linker map for that chip.  (Probably the latter, since it's harder to notice.)

 

avr-gcc 8.2.0 ... don't have ready access to a windows machine

So ... what OS are you running, where did you get your compiler (which is way past the Atmel latest version), and how did you install the tiny1616 support?

 

 

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

That's some incredible sleuthing! Thanks for taking the time to dig through this!

 

I'm running Arch Linux and using the base repository packages for avr-gcc, avrdude, etc. In case it's important, here's the link to the compiler package, which claims to use the official GNU GCC site as it's upstream link.

 

Importantly, the avr-libc package does not support the 1-series ATtiny's, so I followed advice from Petter Breedveld in his ATtiny course here, and copied the provided io.h and iotn1616.h from here, which came from an install of AS7. I'll try copying over the io.h and iotn1616.h files from the Windows computer I tested on when I get the chance, but I'm liking your suggestion that it might be the linker map. Do you know what that file might look like or where I could find it?

 

Thanks again!

S

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

You can download the device support package from http://packs.download.atmel.com/ . The gcc specifics are under gcc (you need both libdev and the spec file)

:: Morten

 

(yes, I work for Atmel, yes, I do this in my spare time, now stop sending PMs)

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

What a trap. Fortunate that I asked for the .lss file, even though I don't think I'd have picked the problem. Fortunate too that address 0x0102 was not read/write (some peripheral registers are). Could have caused all sorts of weirdness. I was going to suggest making x a register variable and that would have "fixed" the problem and we'd all go away wondering why.

 

A newby question: What file or files tell the linker where to put stuff in memory? The .h files tell the compiler where fixed things are (peripherals, ISR vectors) but the location of main() is dependent on the size of the preamble which may vary? and only the linker knows that. So having the right .h files may not be enough?

 

And how does one mark this problem as solved?

Last Edited: Fri. Jan 4, 2019 - 10:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What file or files tell the linker where to put stuff in memory?

Several files are involved.  In this case, I think you're probably missing the "device-specs" file, causing the compile to use some inappropriate defaults.  See this message for how to install packs into a cli toolchain:

 

https://www.avrfreaks.net/comment/2526416#comment-2526416

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

westfw wrote:

What file or files tell the linker where to put stuff in memory?

Several files are involved.  In this case, I think you're probably missing the "device-specs" file, causing the compile to use some inappropriate defaults.  See this message for how to install packs into a cli toolchain:

 

https://www.avrfreaks.net/comment/2526416#comment-2526416

Not me, it's sherazz who had the problem. I followed because I am trying to learn the ins and outs of avr, looking at other people's problems is teaching me heaps. I've only used AS7 and it hasn't given me grief [so far]. If [when] it does, this exercise has opened my eyes to a whole new world of possible pain - and the means to solve it.

 

I also answered my own question, it seems the person who started the thread has a button to say problem solved. And I think your post nails it.

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

I'd agree! Sorry I'm new here and didn't realize that I could mark solutions. Thanks for the info about the support packs @meolsen and @westfw! I'm pretty sure that is the way to fix my problem, but I am running into a different issue now. My compiler is now responding with this error:

 

/tmp/ccFXttI2.s: Assembler messages:
/tmp/ccFXttI2.s:488: Error: pseudo instruction `__gcc_isr' not supported
/tmp/ccFXttI2.s:533: Error: pseudo instruction `__gcc_isr' not supported
/tmp/ccFXttI2.s:535: Error: pseudo instruction `__gcc_isr' not supported

 

A quick google search brought this up (https://www.spinics.net/lists/gc...), so I wonder if it's the newer gcc version that doesn't support this pseudo instruction? I'll try downgrading and report back when I can.

 

Thanks as always,

S

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

The specs file you are using is incompatible with avr-gxx v8+ as it misses gas option to enable __gcc_isr, cf. GCC v8 release notes and the related Binutils PR. If you use custom specs files derive them from the ones natively generated and istalled by gcc.

avrfreaks does not support Opera. Profile inactive.