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 far
1. Set DDRB to 0x0 (default, but whatever), this is input
2. Set PORTB to 0x7 (bits 0,1,2), this enables pullup on the interrupts
3. Set PCMSK1 to enable PCINT8, PCINT9, PCINT10.
4. Set GIMSK bit 5 to high to enable the pin change interrupt
5. 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 word
The 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 this
cli
rcall dds_isr
sei
reti
the dds_isr starts with
in r21, 0x18
[code]
This should copy PORTA into r21 where I can check it. I bit check it using very simple code such as
[code]
ldi 24, 1
and r24, r21
cpi r24, 1
breq skip_cycle ; Bit is high, so skip it
; Asssembler here to change the byte of the DDS phase word
skip_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 LED
If 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 setup
No transformer here, I have a 100 ohm resistor in place of the transformer. So it's just a big voltage divider
Scope shot of output
A 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