I am posting this up because I've really hit a wall here, and I'm hoping to find a direct solution, otherwise I'll have to switch to a Wire library that doesnt use interrupts. The program below is a simple Sinewave Generator, wherein I am supposed to get the analog Sine output from an I2C DAC (MCP4725). I borrowed most of the code from Amanda's Waveform Generator here: http://www.instructables.com/id/Arduino-Waveform-Generator/
But I modified her code and stripped it down to its bare essentials.. and replaced her Parallel Port outputs with I2C instead, focusing on outputting only a Sine wave from the I2C DAC and nothing more.
I included the option for the ISR to generate DAC output either via Adafruit's I2C DAC library OR via my own function. Am not sure if this would help anyone later, but have a look at the simple I2C function I wrote below, 'SendToI2cDAC', that's called by Timer1's ISR. The problem here is that I can get an analog output if this I2C function is called from the main loop() but not when it is called from within the ISR. I have taken the usual precautions within the ISR function, such as avoiding Serial prints and using a volatile variable 'flgTimer' in order prevent the ISR from calling itself when it is already executing. But I still get absolutely NO output from MCP4725 and it's quite frustrating to say the least.
So here's part of my code (full program is attached below).. does anyone have any ideas as to how to get I2C working within the ISR?? And before anyone suggests moving the I2C function back to loop(), I want to make it clear that the very reason that I'm calling it from within the ISR is to ensure that the output is sent out at a fixed sampling rate. And yes, I have already tried enabling interrupts() within the ISR and disabling them as well, but none of these combinations help the I2C commands to go through successfully.
void SendToI2cDAC(unsigned int value){ //earlier, this function returned a combined byte value instead of void, but see comment at end of this function
I2Cbuffer[0] = 0b01000000; //Sets the buffer0 with control byte (010-Sets in Write mode)
I2Cbuffer[1] = value >> 4; //Puts the most significant bit values
I2Cbuffer[2] = value << 4; //Puts the Least significant bit values
Wire.beginTransmission(MCP4725); //Joins I2C bus with MCP4725 at 0x62 address
Wire.write(I2Cbuffer[0]); //Sends the control byte to I2C
Wire.write(I2Cbuffer[1]); //Sends the MSB to I2C
Wire.write(I2Cbuffer[2]); //Sends the LSB to I2C
Wire.endTransmission(); //This line starts the actual transmission
//return(I2Cbuffer[1] | I2Cbuffer[2]); //what WEIRDness! if this return is commented out and function changed to void, then Serial WORKS in loop but SLOWLY!! Hurray?? :/
}
//------------------------------------------------------------------------------------
ISR(TIMER1_COMPA_vect){ //timer 1 interrupt
//UNFORTUNATE NOTE: ANY ATTEMPT TO CALL A SERIAL OR I2C FUNCTION WITHIN THIS TIMER INTERRUPT SEEMS TO FAIL MISERABLY
if(!flgTimer) return; //existing call has been interrupted while already processing an interrupt, so exit! Without this line, Arduino will hang and you'll need to Reset and/or upload an empty sketch just to get it back to normal
flgTimer=false;
//increment wave's t and reset each time it reaches period
t++;
if(t>=period) t=0;
wavNum = t*wavInc; //calculate the offset you need to read the required sine value from the Lookup array
wave = pgm_read_word(&(SineLookupForDAC[wavNum]));
//Depending on the interrupt source, you may need to clear the interrupt flag here. Most Arduino interrupts are self-clearing.
interrupts();//by default, interrupts are disabled in a timer interrupt, so re-enable them for I2C or SPI to work (EDIT: Doesn't seem to help either way)
//Now send the final Output to the DAC within the Timer Interrupt itself -> supposed to give accurate output
if(UseAdaI2cDACfunc) dac.setVoltage(wave, false);
else SendToI2cDAC(wave); //previously => combinedValue = SendToI2cDAC(wave)
//noInterrupts(); //turn off interrupts so we can't be interrupted while resetting our special variable
flgTimer=true;
}
//------------------------------------------------------------------------------------
Also, here's something weird that happened. Earlier, I had included Serial prints in the ISR, which I soon realized was a big no-no. So, I moved them to the main loop() instead. Initially, I had no luck with receiving any serial prints even from the loop function. But it's the weirdest thing, for SOME reason, if I comment out the return value in the SendToI2cDAC function and change it to void, I do see the prints on the Serial Monitor but they come in verrryyy SLOWWLYYY, lol. I still dont get any analog output from the MCP DAC, so the Wire calls are clearly failing. As for the Serial output, I assume the Timer interrupt is happening so fast, that the Serial is only able to print out what's left in its buffer? (not sure if that's the right terminology for Arduino). But has anyone experienced this kinda weirdness before?
I2cDACwithinTimerISR.ino (10.5 KB)