Checking which pin triggered on a port triggered an interrupt on attiny84 - Page 1
Forum section: electronics / general

author: hydrogen18
author_rank: Contributor
timestamp: December 07, 2017, 04:27:23 pm
content: I have this somewhat silly frequency generator project I've been working on.The brief description is I built a 5-bit ADC converter using an exponential resistor series, 2N7000 logic level MOSFETs and an attiny84. Instead of generating a sine wave between 0 and 2*pi, I'm generating a wave between 0 and pi. I added two bits to my ADC (7 total now) that emit square waves that are in phase with the sine wave but 180 degrees out of phase with each other. Basically the idea is I can drive a center tapped transformer and get +/- by using the square waves to toggle which half of my transformer has current in it.But enough about the analog portion. I'm aware this is a pretty silly way to generate a signal but I've had fun building it so far. What I'm struggling with is the interrupt code in avr-gcc and assembler. I'm trying to use PCINT8, PCINT9, and PCINT10 on the chip. Here is what I have figured out so far1. Set DDRB to 0x0 (default, but whatever), this is input2. Set PORTB to 0x7 (bits 0,1,2), this enables pullup on the interrupts3. Set PCMSK1 to enable PCINT8, PCINT9, PCINT10.4. Set GIMSK bit 5 to high to enable the pin change interrupt5. Set an entry in the vector for PCINT1_vect to jump to whatever I want.I'm using avr-gcc to build this, but most of it is assembler. I have a main that does setup before jumping to my assembly code which does DDS.Since I need some visual output, I added an LED that is tied via a 2200 ohm resistor to +5 volts on my board. The other end goes to PA6 which is one of my square wave output pins. So a low signal on this enables the LED. Under normal circumstance this guy runs a 50% duty cycle and lets me know that at least something is running. When my ISR runs, I set all the D->A bits to zero. All the MOSFETs are off, so nothing has any current. I then just wrote a C routine that blinks the LED by toggling PA6in PORTA. Since the MOSFETs are off I've got no current in my transformer. This gives me a visual output other than hooking up my scope.The purpose of each interrupt is as follows* PCINT8 - Toggle the byte of the DDS phase word that is being changed* PCINT9 - Increment selected phase word byte* PCINT10 - Decrement selected phase wordThe phase word of my DDS is r24, r25, r26. The interrupt service routine has some additional constraints, such as r24 can't decrement below 1 and r26 can't be incremented to more than 0x7f.My interrupt service routine runs and does thisCode:clircall dds_isrseiretithe dds_isr starts withCode:in r21, 0x18This should copy PORTA into r21 where I can check it. I bit check it using very simple code such asldi 24, 1and r24, r21cpi r24, 1breq skip_cycle ; Bit is high, so skip it; Asssembler here to change the byte of the DDS phase wordskip_cycle:The idea is to AND the value in r21 with a known bitpattern and then check to see if it is still the same value. If it is, the bit is still set, so pullup hasn't happened.Since I've got my blink routine, I also setup some extra code to do the following* PCINT8 - 1 blink of LED* PCINT9 - 2 blink of LED* PCINT10 - 3 blink of LEDIf no bits are found to be pulled low, 4 blinks of the LED is performed. Calling the C - routine involves saving r23-r31, but this is just a bunch of push/pop around the call. Nothing fancy.Photo of the physical setupNo transformer here, I have a 100 ohm resistor in place of the transformer. So it's just a big voltage dividerScope shot of outputA stepped (crummy) inverted sine wave since I've got a voltage divider hooked up.I know my ISR is running and working! But I always get 4 blinks of the LED when I trigger it. The 3 jumpers up in the top left have 10k resistors going to the PORTB pins and the other pin is just ground. So shorting them with a screwdriver triggers it. But I never get anything other than 4 blinks! Is "in r21, 0x18" not sufficient to capture the state of PORTB? Do I just absolutely have to use something with some sort of flip-flops to capture the state of the pins physically? Is there a chip i can use to do this? Any help you guys can provide would be great.Here are some links to my complete code and the refs for the attiny84* my main.c -https://github.com/hydrogen18/bench_freqgen/blob/ca8ccd0eebbddd309637254cf87f1fa272d84ac5/main.c* my DDS assembler code -https://github.com/hydrogen18/bench_freqgen/blob/ca8ccd0eebbddd309637254cf87f1fa272d84ac5/dds.S* spec sheet for attiny84 -http://www.atmel.com/images/doc8006.pdf

author: hydrogen18
author_rank: Contributor
timestamp: December 07, 2017, 05:07:50 pm
content: So I had an idea on this, which is keep running "in r21, 0x18" until I get one of the bits in r21 & 0x7 set to low. I tried to write a loop that runs this 32768 times. I'm unsure if it is working. My "dds_isr" now starts with this.Code:dds_isr:push r19push r20ldi r19, 0x00ldi r20, 0x80read_input_port:in r21, 0x18andi r21, 0x7cpi r21, 0x7brne done_reading_input_portsubi r19, 0x1sbci r20, 0x0breq done_reading_input_portrjmp read_input_portdone_reading_input_port:pop r19pop r20The idea is r20:r19 makes up a 16 bit counter. If it counts to zero the loop breaks (to prevent staying in the ISR forever). Doing "andi r21, 0x7" should leave us with only the lowest 3 bits in r21. Executing "cpi r21, 0x7" checks it and if they aren't equal then the "brne" jumps out of the loop.However, I am still just getting 4 blinks when my ISR runs. I'm out of ideas.