Here it is "magic code" that re-enables SD card for reading. I'm not going to pretend I understand most of it, but these is bare minimum code I was able to extract from WaveHC library (specifically SdReader.cpp) in order for it to resurrect SD card after RFM69 recieved data...
I measured timing and it takes 1-122 milliseconds to execute (usually 1-2 but sometimes I see it takes 122, that's when waitNotBusy function is running)...
void sdReset() {
byte r;
// initialize card and send host supports SDHC if SD2
for (uint16_t t0 = millis();;) {
cardCommand(CMD55, 0);
r = cardCommand(ACMD41, SD_CARD_TYPE_SD2 ? 0X40000000 : 0);
if (r == R1_READY_STATE) break;
}
}
/** Send a byte to the card */
void spiSend(byte b) {
SPDR = b; while(!(SPSR & (1 << SPIF)));}
/** Receive a byte from the card */
byte spiRec(void) {spiSend(0XFF); return SPDR;}
// send command to card
byte cardCommand(byte cmd, uint32_t arg) {
byte r1;
// wait up to 300 ms if busy
waitNotBusy(300);
// send command
spiSend(cmd | 0x40);
// wait for response
for (byte retry = 0; ((r1 = spiRec()) & 0X80) && retry != 0XFF; retry++){
}
return r1;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
byte waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
while (spiRec() != 0XFF) {
if (((uint16_t)millis() - t0) > timeoutMillis) return false;
}
return true;
}
Just execute sdReset() after all radio stuff is done (i.e. send ACK, etc.)
Hope it helps someone who might experience similar conflict. And if anyone can understand what this code does, I'd love to hear explanation! :)
I'm still banging my head on the wall over this one. My "workaround" didn't work in long run, whole micro-controller freezes when radio signal comes in while it's playing WAV file from SD Card.
Felix as you suggested, I was able to figure out how to disable correct interrupt and it works with SD card
detachInterrupt(digitalPinToInterrupt(2));
But to get Radio working again I need enable it, and so far I couldn't figure out how to do it...
In your library it ran during init:
attachInterrupt(_interruptNum, RFM69::isr0, RISING);
I've tried running this from my sketch:
attachInterrupt(digitalPinToInterrupt(2), radio.isr0(), RISING);
But it gives me error:
RFM69.h:122:17: error: 'static void RFM69::isr0()' is protected
Is there any way I can attach interrupt within my program?
Just a coding note:
isr0 is a static function - you don't need the 'radio' variable instance to access it or call it. In your attachInterrupt code, you want to pass the function, not call it and pass the return value. So:
// WRONG:
attachInterrupt(digitalPinToInterrupt(2), radio.isr0(), RISING);
// RIGHT:
attachInterrupt(digitalPinToInterrupt(2), RFM69::isr0, RISING);
Of course it's still protected. But if you wanted to inherit from RFM69, you can do something like this and then call the add/del methods to take care of the interrupt.
class MyRFM69 : public RFM69 {
public:
// Pass through constructor
MyRFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN,
bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM)
: RFM69(slaveSelectPin, interruptPin, isRFM69HW, interruptNum) {
}
void enableInterrupt() {
attachInterrupt(_interruptNum, RFM69::isr0, RISING);
}
void disableInterrupt() {
detachInterrupt(_interruptNum);
}
};
Just call radio.initialize() again. It will reattach its own interrupt. You could also simply mask and unmask interrupt 2. A simple DAGS will provide code for this.
Thanks Tom! I actually am calling radio.initialize() every time after Audio finished playing. I think I'm also have call radio.encrypt() as well, so I'm doing it just in case.
I'm not sure I understand what do you mean by unamsk interrupt? And what is DAGS?
// ==================================================
// -- Turns off radio and keeps track of it's status
void turnOffRadio() {
if (!isRadioPresent) return;
//radio.Sleep();
if (radioOn) {
//radio.sleep();
radioOn=false;
putstring_nl ("Radio Off!");
delay (5);
detachInterrupt(digitalPinToInterrupt(2));
}
}
// ====================================================================
// -- Re-initializes radio after it was diabled by interrupt function
void reEnableRadio() {
if (!isRadioPresent) return;
if (radioOn) return;
if (isInMenu) return;
if (soundAlarm[0] || soundAlarm[1]) return;
if (wave.isplaying) return;
if (isInQMenu) return;
putstring_nl("Re-enable Radio");
radio.initialize(FREQUENCY, NODEID, NETWORKID);
radio.encrypt(KEY);
radioOn=true;
radio.sleep();
card.init(); // Reset SD Card
}
So before playing audio I call turnOffRadio() function. reEnableRadio() is running in main loop, and once it sees it can do it's thing it reinitialize radio (and SD card). This seems to work pretty well, but probably uses unnecessary resources.
TD22057, thanks so much for your code! I'll try to add it to the library.
FYI I'm using SD Library that's part of WaveHC library (by Adafruit). Not sure how to integrate another one.
For now I'm going to see if I can resolve this issue in software. I finally ported my code to work with Both RFM12b and RFM69. Had to build RFM12b weather sensor and so far it's working... But time will tell.
I hope it locks up, then I can try hardware solution (resistors)....
BTW if anyone interested to write code for both modules, it's quite easy, just use defines..
//#define RFM69_CHIP // Comment out for RFM12b
#if defined (RFM69_CHIP)
#include <RFM69.h>
#else
#include <RFM12B_arssi.h>
#endif
#if defined (RFM69_CHIP)
RFM69 radio;
#else
RFM12B radio;
#endif
... and so on...