I have a DDS that is controlled by an Arduino DUE, loop() waits for Serial commands and based on them calls one or another function that sets the DDS's frequency, phase, amplitude etc via SPI. In addition to that I want to be able to use an external interrupt triggered by a TTL signal to reset the DDS's phase accumulator. The phase reset is done by writing an SPI register - resetPhase().
Somehow the resetPhase() is triggered correctly, but as soon as I add a SPI.transfer to it the SPI communication stops working altogether, not just through interrupts, but also the functions triggered via serial commands stop working.
Is there a way to get it to work?
SPISettings spiSettings = SPISettings(10000000, MSBFIRST, SPI_MODE0);
void setup()
{
pinmode(chipSelect, OUTPUT);
int syncPIN = digitalPinToInterrupt( interruptPin);
SPI.usingInterrupt(syncPIN);
attachInterrupt(syncPIN, resetPhase, RISING);
}
void resetPhase():
{
SPI.beginTransaction(spiSettings);
digitalWrite(chipSelect, LOW);
SPI.transfer(controlRegister);
digitalWrite(chipSelect, HIGH);
SPI.endTransaction();
}
1 Answer 1
In general, it's best to do as little as possible in your interrupt service routine (ISR).
resetPhase
is your ISR here, and typically it would set a flag or semaphore to signal lower priority code that certain work needs to be done and, in this case, probably nothing more. Then your loop
code on noticing the flag is set would clear the flag and do its work.
I imagine the library authors thought SPI.usingInterrupt
would ease use of SPI, but performing I/O in an ISR seems a bit contrary to best practices. These concerns are echoed here, along with some other caveats regarding interrupts and ISRs. Possibly not the answer you're looking for, but I hope it helps.
// If SPI is used from within an interrupt, this function registers // that interrupt with the SPI library, so beginTransaction() can // prevent conflicts. The input interruptNumber is the number used // with attachInterrupt. If SPI is used from a different interrupt // (eg, a timer), interruptNumber should be 255. static void usingInterrupt(uint8_t interruptNumber);