Author Topic: SPI Conflict between RFM69 and SD library  (Read 28764 times)

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
SPI Conflict between RFM69 and SD library
« on: January 24, 2016, 09:19:45 PM »
I have a question about RFM69 library.
In my Xronos clocks I used to use both RFM12b and my version of WaveShield with SD card.  Since RFM12b and SD Card share SPI bus I used different SS pins for each. I still had conflict between too, but I was able to remedy it by putting RFM12b into sleep with radio.sleep() command just before playing wave from SD card. This worked pretty well.
Now I built new version with RFM69 chip and this trick doesn't work anymore... :(
As soon as I initialize RADIO, SD card stops working... Both work on their own but not together. radio.sleep no longer does the trick, it must work different in new library...
Just FYI I'm using ATMega1284p. SS for RFM is D18 (I use radio.setCS(18))  and for SD card it's D4.
Is there some kind of command that disables RFM69 chip temporary other than sleep()?

emjay

  • Full Member
  • ***
  • Posts: 119
  • Country: nl
Re: SPI Conflict between RFM69 and SD library
« Reply #1 on: January 25, 2016, 02:55:49 AM »
You have a firm pullup on D18?

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: SPI Conflict between RFM69 and SD library
« Reply #2 on: January 25, 2016, 06:33:15 AM »
I did a project some time ago that shared the SPI bus with an SD card. You might want to look at the MISO signal with a 'scope, I found that some SD cards don't release their MISO signal to high impedance when its chip select is inactive. You'll see if that happens because you'll get an undefined logic level on the MISO. The solution was to place a 470R resistor between the SD card's MISO and the MCU, that way whatever you're accessing can overdrive the MCU's MISO.

Mark.

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #3 on: January 25, 2016, 07:36:40 AM »
Yup I have 10K pullups on both SS.
Mark, thats interesting, I'll check MISO with scope. Althogh  in my case RFM overrides SD card. I made a little progress. If I initialize SD card after RFM, I can read files, but as soon as data pocket comes over radio I no longer able to read SD. Its like RFM refuses to release SS. I'll check it with scope today...

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: SPI Conflict between RFM69 and SD library
« Reply #4 on: January 25, 2016, 08:07:19 AM »
OK, it could be the other way round (I presume you mean it's like the RFM is not releasing MISO to high impedance, the SS is controlled by the MCU). Maybe the state of the MISO pin from the RFM actually determines whether the SD card can override it and that state could be different from the initialization state after a packet has been received. That would explain things, but your 'scope is going to show something. The solution might be the other way round then, either add a tri-statable buffer between the RFM' MISO and the MCU or put a 470R resistor between it and the MCU.
Mark.

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #5 on: January 25, 2016, 09:03:22 AM »
Will try that too. Although I'm a noob when it comes to scope, so I need to figure that out :)
Done more testing before going to work. This time I was only sending data without requesting for ACK. 
i.e. send pocket, read SD card and it works great. I'm able to read SD card right after transmitting even without putting radio to sleep!  But if I do request for ACK it locks SD card :( So Transmissions are ok, receives do not release SPI or SS line. 
Maybe Felix has a suggestion since he knows his code best :)

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: SPI Conflict between RFM69 and SD library
« Reply #6 on: January 25, 2016, 10:47:36 AM »
I use SD  card in my gateways using the same SPI interface as the radio and did have an issue with older version cards. HC cards work well.
Tom

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #7 on: January 25, 2016, 12:03:02 PM »
I use SD  card in my gateways using the same SPI interface as the radio and did have an issue with older version cards. HC cards work well.
Tom
What kind of issues did you have?

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: SPI Conflict between RFM69 and SD library
« Reply #8 on: January 25, 2016, 01:05:48 PM »
My first thought is that you might need to stop interrupts from the radio with noInterrupts(), then do your SD work, then reenable with interrupts().

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #9 on: January 25, 2016, 02:13:55 PM »
My first thought is that you might need to stop interrupts from the radio with noInterrupts(), then do your SD work, then reenable with interrupts().
Thanks Felix. No unfortunately noInterrupts() also kills Audio playback :( I think DAC uses internal interrupts as well...

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: SPI Conflict between RFM69 and SD library
« Reply #10 on: January 25, 2016, 02:16:41 PM »
Then just specifically disable the interrupt on pin D2 (interrupt 0 of the atmega328p).

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #11 on: January 25, 2016, 02:41:18 PM »
Then just specifically disable the interrupt on pin D2 (interrupt 0 of the atmega328p).
Good idea! I tried it, but it didn't work :( 
detachInterrupt (2); (tried 0 and 1 as well)
Meanwhile I found a workaround... If I call "initialize" SD Card command before next read, it works. I'm now trying to "deconstruct" and understand that part of SDReader.cpp library to see which action gives control back to SD card...
« Last Edit: January 25, 2016, 05:41:13 PM by Lensdigital »

Lensdigital

  • Full Member
  • ***
  • Posts: 155
    • Lensdigital
Re: SPI Conflict between RFM69 and SD library
« Reply #12 on: January 25, 2016, 05:46:22 PM »
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)...
Code: [Select]
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! :)

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: SPI Conflict between RFM69 and SD library
« Reply #13 on: January 25, 2016, 07:57:40 PM »
Just wondered if you've been able to look at MISO at all. One thing you could try is simply read a single byte from it rather than initialize as a read uses 0xFF as the write data, this would leave MISO high. Also try reading but using 0x00 as the write data instead to leave MISO low. Just curious if it has an effect.
Mark.

oric_dan

  • Jr. Member
  • **
  • Posts: 64
Re: SPI Conflict between RFM69 and SD library
« Reply #14 on: January 25, 2016, 09:08:37 PM »
Trying to share the SPI port between multiple devices is fraught with potential problems. The original Arduino SD libraries had the MISO hang problem, the newer libraries have supposedly this fixed. I'm not sure which library Moteino uses. Whether this is the current problem or not, the following thread may be of some interest:
http://forum.arduino.cc/index.php?topic=276274.0

This is an especial problem when SPI uses hardware [external] interrupts. FWIW, the Teensy guy attempted to create a workaround with his beginTransaction() and endTransaction() functions, but I don't know how effective his solution is [also, I've never ever been able to figure out how interrupts work on the Teensy boards using ARM chips].

So, I'm tossing this out _ONLY_ in the case anyone wants to take the time to try and figure "Transactions" out [!!!], but I don't understand it very well myself:
http://www.pjrc.com/teensy/td_libs_SPI.html
« Last Edit: January 26, 2016, 02:39:29 PM by oric_dan »