We continue on our Embedded C Atmel MCU adventure.....
Quick one this time as I build my way to an improved Dirty Digital LFO. I don't want to forget what I've done so far so perhaps this post is mostly for me?
One of my favorite dev boards for Atmel Embedded C programming is the Arduino Uno R3. To get the background on Interrupts for this board, using Embedded C, you may want to read the previous post here. |
Interrupts are key in many digital audio projects, in the case of the "dirty digital LFO" I created a waveform reset to zero buffer PCB using a 3904 transistor and a few resistors--post for that is here.
I am now rebuilding the ddlfo using a lookup table, and I also want to make it so an incoming square wave or pulse signal resets the LFO's output frequency to zero, and finally have that work in parallel with a frequency counter (post here).
But--can we get the existing DDFO reset circuit to work with what is essentially very different code? Yes. That's one of the major advantages of embedded C; you get something to work, then drop code and hardware fragments from old projects into new ones. Modularity is a primary reason I made the switch from a highly abstracted programming language to Embedded C for my AudioDiWHY projects.
Get down to it: The inverter/buffer circuit and PCB shown above is covered in the post here. Lots of ways to do this, but since my sponsor, PCBWAY, sent me a few 3904 buffer PCBs and I've only used one to date, I might as well use what I already have on hand.
To make this work I created a very simple gate to trigger on a breadboard using a single .001 cap and a 47K resistor; trial and error indicated that this worked best for my modular rig. The output resistor R5 for the buffer is set at 1K, not 22K as in the original DDLFO design. For proof of concept I am using an MCP4911 DAC, which I like due to its simplicity.
To make the 4911 DAC go, I used existing MCP4921.c and .h code from my github page, here, and modified it slightly to accommodate 10 bits at output vs. the 4921's 12 bit output. the core "wave reader" code was written from scratch.
I will post this code including the 4911 driver file when I have this "wavewalker" LFO working--should be pretty soon?
The last thing to do was put it on the bench to test:
....using this code fragment before the "main loop":
/**********INTERRUPT ********/
ISR (INT1_vect)
{
x = 0;
_delay_ms(5);// "Riley Reset", incoming interrupt resets LFO wavefrm to zero
}
/**************************/
/**********Set up Riley reset timer************/
EIMSK |= 1<<INT1; /* enable external interrupt 1 (D2 pin on Uno R3) */
EICRA |= 1<<ISC11; /* interrupt on edge (trig) */
//EICRA |= ~(1 << ISC10); /* interrupt on low (trig) */
EICRA |= 1 << ISC10; /* interrupt on high (trig) */
sei(); /* enable interrupts */
This worked. The wavewalker design, so far, starts at cell 0 of a 200 cell uint_16 array and steps through the array sequentially; there is a pause between each read. This delay() sets the overall frequency--longer pauses mean a slower frequency at output.
So--to perform a waveform reset is pretty simple, you tell the system to start reading at cell [0] each time an interrupt is seen.
On the bench it works, but I see an occasional need to better debounce the interrupt signal. For the LFO "wavewalker" design to date: what you see above seems good enough.
I need to next tweak the frequency counter (post here) to multiply it by 15 or 30 (how I arrived at these constants will be covered in a future post), then create another lookup table match the observed incoming frequency to the delay between array reads. That should allow BPM to frequency conversion for the LFO.
This will hopefully make more sense when I post the wavewalker design, which I hope to have working sometime this month. I am now going to pull apart the breadboard dookie you see above to further tweak the frequency counter subcircuit, so what you see blogged today is all I have for the interrupt portion of the design, at least for now.
Stay tuned.
No comments:
Post a Comment