Getting Virtual Wire and SdFat to work together, storing messages on microSD

Hi.

As part of a university summer project I need to wirelessly transfer some data from one Arduino board with a microSD attached to another Arduino board with microSD. I have had success with the transmission side of things and have working code that can read text from a txt file and then transmit whatever is read. I know this code works fine as I have seen the transfer on the receiving serial monitor.

My problem is with the next stage - writing the received data to a microSD. I am using the Virtual Wire library for the wireless and SdFat for the storage. My code on the receiving Arduino is as follows:

//Attach receiver module facing outwards from pins 2 to 5 for no breadboard setup

#include <VirtualWire.h>
#include <SdFat.h>

//Virtual Wire initialisations
const int receive_pin = 3;
const int transmit_en_pin = 7;
const int Vpin = 2;
const int GND = 5;

//SdFat initialisations
SdFat sd;
SdFile myFile;
const int chipSelect = 4;

void setup()
{
    delay(1000);
    Serial.begin(9600);	// Debugging only
    Serial.println("setup");    
    // Initialise the IO and ISR
    vw_set_rx_pin(receive_pin);
    vw_set_ptt_pin(transmit_en_pin);
    vw_set_ptt_inverted(true); // Required for DR3100
    pinMode(Vpin, OUTPUT); // Sets up pins for use
    pinMode(GND, OUTPUT);
    digitalWrite(Vpin, HIGH);  // Sets up pin voltage levels
    digitalWrite(GND, LOW);
    
    if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
     sd.initErrorHalt(); // If fails then error
    
    if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
     sd.errorHalt("opening rx.txt for write failed");  // If fails then error
            
    vw_setup(2000);	 // Bits per sec
    vw_rx_start();       // Start the receiver PLL running

}

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen)) // If a message is received...
    {       
      for (int i = 0; i < buflen; i++) //For each received byte...
	{
            Serial.print((char)buf[i]);
	    myFile.println((char)buf[i]); //Write single byte to to myFile, rx.txt
	}
      myFile.close();
     }
     
}

The problem is that received messages do not appear on the receiving serial monitor nor the receiving microSD (though the file “rx.txt” is created, it is just blank).

Is there some blaring misuse of the libraries here? I’m new to Arduinos but my transmission code is written in a similar way and works fine.

Any and all advice here would be appreciated and if I have missed out information then please ask. Thanks.

EDIT: The RF modules used are eBay’s finest (http://www.ebay.co.uk/itm/161292991774) at £2. They are cheap but functional and I have had no issues with them.

Here is the code for my transmitter. If has any bad practice I’d appreciate knowing but it does work (I swear!).

//Connect transmitter facing inwards to pins A3, A4 and A5

#include <VirtualWire.h>
#include <SdFat.h>

SdFat sd;
SdFile myFile;

const int led_pin = 11;
const int transmit_pin = A5;
const int receive_pin = 2;
const int transmit_en_pin = 3;
const int chipSelect = 4;

void setup()
{
    // Initialise the IO and ISR
    vw_set_tx_pin(transmit_pin);
    vw_set_rx_pin(receive_pin);
    vw_set_ptt_pin(transmit_en_pin);
    vw_set_ptt_inverted(true); // Required for DR3100
    pinMode(A3, OUTPUT);
    pinMode(A4, OUTPUT);
    pinMode(A5, OUTPUT);
    digitalWrite(A3, LOW);
    digitalWrite(A4, HIGH);    
    
    vw_setup(2000);       // Bits per sec
    
   Serial.begin(9600);
  while (!Serial) {}  // wait for Arduino
  
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

  // open the file for reading:
  if (!myFile.open("pack.txt", O_READ)) {
    sd.errorHalt("File read failed!");
  }
  char data;
  
  while ((data = myFile.read()) >= 0){
        
    char msg[1] = {data};
    delay(100);
    vw_send((uint8_t *)msg, 1);
    vw_wait_tx(); // Wait until the whole message is gone
    delay(100);
  }
  // close the file:
  myFile.close();
}

void loop()
{ 
}

In your receiver code, you are opening myfile in setup();
and according to your code after receiving any data (vw_get_message(buf, &buflen)) it writes to file and close the myfile.
Now, once again when you receive any message you are not able to write to file because it is already closed.
so you need to reopen the file once you receive the data and after writing to file close it.

Hi Bijendra, moving both of the if statements and the file close to be within the for loop has got it writing!

The only problem now is that only the first array of bytes transferred gets written. I imagine that indicates that I have put something in the for loop that shouldn’t be there?

Right now the code is:

//Attach receiver module facing outwards from pins 2 to 5 for no breadboard setup

#include <VirtualWire.h>
#include <SdFat.h>

//Virtual Wire initialisations
const int receive_pin = 3;
const int transmit_en_pin = 7;
const int Vpin = 2;
const int GND = 5;

//SdFat initialisations
SdFat sd;
SdFile myFile;
const int chipSelect = 4;

void setup()
{
    delay(1000);
    Serial.begin(9600);	// Debugging only
    Serial.println("setup");
    
    // Initialise the IO and ISR
    vw_set_rx_pin(receive_pin);
    vw_set_ptt_pin(transmit_en_pin);
    vw_set_ptt_inverted(true); // Required for DR3100
    pinMode(Vpin, OUTPUT); // Sets up pins for use
    pinMode(GND, OUTPUT);
    digitalWrite(Vpin, HIGH);  // Sets up pin voltage levels
    digitalWrite(GND, LOW);
    
    vw_setup(2000);	 // Bits per sec
    vw_rx_start();       // Start the receiver PLL running

}

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen)) // If a message is received...
    {       
      for (int i = 0; i < buflen; i++) //For each received byte...
	{
          if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
          sd.initErrorHalt(); // If fails then error
    
          if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
          sd.errorHalt("opening rx.txt for write failed");  // If fails then error
            
          Serial.print((char)buf[i]);
	  myFile.println((char)buf[i]); //Write single byte to to myFile, rx.txt
	  
          myFile.close();
        }
      }     
}

Thanks a lot for the help :slight_smile:

in your code, Inside

for (int i = 0; i < buflen; i++) //For each received byte...
	{
// for every  iteration you are initializing the the sd card, opening and closing  the myfile.
// that might b creating a problem( i dont have sd card to test.)  
          if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
          sd.initErrorHalt(); // If fails then error
    
          if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
          sd.errorHalt("opening rx.txt for write failed");  // If fails then error
            
          Serial.print((char)buf[i]);
	  myFile.println((char)buf[i]); //Write single byte to to myFile, rx.txt
	  
          myFile.close();
        }

you need to do like this:

if (vw_get_message(buf, &buflen)) // If a message is received...
    {   
      if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
      sd.errorHalt("opening rx.txt for write failed");  // If fails then error    
      if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
      sd.initErrorHalt(); // If fails then error
      for (int i = 0; i < buflen; i++) //For each received byte...
      {      
          Serial.print((char)buf[i]);
	  myFile.println((char)buf[i]); //Write single byte to to myFile, rx.tx
      }
        myFile.close();
    }

Thank you, that worked perfectly! I was so sure I'd tried exactly that code before posting here but heyhoh, I must have been doing something daft.

Again, thanks :slight_smile:

Sorry for necroing this thread, but which Sdfat library are you using? I keep running into errors with mine.

I imagine it was this version from August.

I also use that one, but the line

SdFat sd;

Keeps showing up as an error, along with several other lines when I copy and paste your sketch..

Keeps showing up as an error, along with several other lines when I copy and paste your sketch…

what error you are getting??

This is what I get when trying to compile the transmitter code:

In file included from sketch_oct18a.ino:4:
G:\Apps\Arduino\Sketches\libraries\SdFat/SdFat.h:294: error: conflicting return type specified for 'virtual void SdFile::write(uint8_t)'
G:\Apps\Arduino\hardware\arduino\cores\arduino/Print.h:48: error:   overriding 'virtual size_t Print::write(uint8_t)'
sketch_oct18a:6: error: 'SdFat' does not name a type
sketch_oct18a.ino: In function 'void setup()':
sketch_oct18a:33: error: 'sd' was not declared in this scope
sketch_oct18a:33: error: 'SPI_HALF_SPEED' was not declared in this scope
sketch_oct18a:36: error: no matching function for call to 'SdFile::open(const char [9], int)'
G:\Apps\Arduino\Sketches\libraries\SdFat/SdFat.h:238: note: candidates are: uint8_t SdFile::open(SdFile&, uint16_t, uint8_t)
G:\Apps\Arduino\Sketches\libraries\SdFat/SdFat.h:239: note:                 uint8_t SdFile::open(SdFile&, char*, uint8_t)
G:\Apps\Arduino\Sketches\libraries\SdFat/SdFat.h:241: note:                 uint8_t SdFile::open(SdFile&, char*)
sketch_oct18a:37: error: 'sd' was not declared in this scope

sketch_oct18a:36: error: no matching function for call to ‘SdFile::open(const char [9], int)’

this error message clearly telling you that Sdfat does not have any overloaded function whose 1st argument is of const char [9], type.
you can pass argument like uint8_t SdFile::open(SdFile&, uint16_t, uint8_t) or other related overloaded functions only.

send your full code …

Hello and thanks for your replies.

My code is the exact same as the transmitter code posted above by Hooby.

hello!
i run your code and did not got any error.
so i suspect you might not added library properly.
goto http://arduino.cc/en/Guide/Libraries

if you still get the same error let us know.

BTW how you added library to transmitter code.?

I've tried to install the library on another PC with IDE 1.0.6 and it compiled correctly there.

I'll try the same on my own PC later this evening, I'll keep you posted.

OK, now I'm clueless. I've installed the library exactly as I did on my other PC and it doesn't compile.

I downloaded the 1.0.6 version and installed the library, no luck, it won't compile.

I'll copy the library files from the other PC tomorrow but I really have no idea what's happening.

Well, I got it figured out. De-installed Arduino, re-installed again and now the SDfat library works.
My older sketches will need an update as they relied on other FAT libaries but I’ll manage.

Anyway, I’ll try the transmitter and receiver code again later this afternoon, I expect it to work now.
After that, It’s time to implement it into my current sketch.

Thanks for your help, most appreciated.

Ok, the transmission is received but not stored correctly when trying the first sketch.
I’ve tried swapping the SDcards but that didn’t help. I ran sdformat on both cards and tried the example ReadWriteSdfat, that worked well.
Now, This is my code:

//Attach receiver module facing outwards from pins 2 to 5 for no breadboard setup

#include <VirtualWire.h>
#include <SdFat.h>

//Virtual Wire initialisations
const int receive_pin = 4;
const int transmit_en_pin = 7;
const int Vpin = 2;
const int GND = 5;

//SdFat initialisations
SdFat sd;
SdFile myFile;
const int chipSelect = 10;

void setup()
{
   delay(1000);
   Serial.begin(9600);	// Debugging only
   Serial.println("setup");    
   // Initialise the IO and ISR
   vw_set_rx_pin(receive_pin);
   vw_set_ptt_pin(transmit_en_pin);
   vw_set_ptt_inverted(true); // Required for DR3100
   pinMode(Vpin, OUTPUT); // Sets up pins for use
   pinMode(GND, OUTPUT);
   digitalWrite(Vpin, HIGH);  // Sets up pin voltage levels
   digitalWrite(GND, LOW);
   
   if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
    sd.initErrorHalt(); // If fails then error
   
   if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
    sd.errorHalt("22opening rx.txt for write failed");  // If fails then error
           
   vw_setup(2000);	 // Bits per sec
   vw_rx_start();       // Start the receiver PLL running

}

void loop()
{
   uint8_t buf[VW_MAX_MESSAGE_LEN];
   uint8_t buflen = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf, &buflen)) // If a message is received...
    {   
      if (!myFile.open("rx.txt", O_RDWR | O_CREAT | O_AT_END)) // Try to open file for write
      sd.errorHalt("opening rx.txt for write failed");  // If fails then error    
      if (!sd.begin(chipSelect, SPI_HALF_SPEED)) //  Try to begin communication with microSD
      sd.initErrorHalt(); // If fails then error
      for (int i = 0; i < buflen; i++) //For each received byte...
      {      
          Serial.print((char)buf[i]);
	  myFile.println((char)buf[i]); //Write single byte to to myFile, rx.tx
      }
        myFile.close();
    } 
    
}

But now I get the error:
error: opening rx.txt for write failed
This is the last error message in the sketch and I can’t find out why. Do I need to close the file in void setup already?

Your IDE usually contains many libraries compatible with it. Use those if possible.

o I need to close the file in void setup already?

If you want to open it again in loop, you do.