Libelium microSD module and duemilanove hassle...

Hi all, I want to log temperature data onto a microSD card. I have

Arduino duemilanove w/ ATMega328 @ 16MHz Libelium microSD module w/ Sandisk 2 GB card @ FAT16, formatted with Panasonic tool. The module is plugged into ICSP. Arduino 0017 sw on Mac OS X 10.6.2

I tried several SD access libraries: Filelogger SDuFAT SdFat

Only SdFat works. I got it to work by changing card.init = (true) in the SdFatInfo code. So I assume all my other failures have to do something with the Libelium board being accessed at 8 MHz, which seems to be too fast. Honestly, SdFat is complicated, and it can do far too much things for me. So I'd ike to keep it simple and use Filelogger, but I can't get it to work: The test code prduces "Fail initializing" errors.

Here is my outpot from SdFatInfo, it seems the setting is ok:

init time: 46

Card type: SD2

Manufacturer ID: 3
OEM ID: SD
Product: SU02G
Version: 8.0
Serial number: 52193440
Manufacturing date: 6/2009

cardSize: 3862528 (512 byte blocks)
flashEraseSize: 32 blocks
eraseSingleBlock: true

part,boot,type,start,length
1,0,6,135,3862393
2,0,0,0,0
3,0,0,0,0
4,0,0,0,0

Volume is FAT16
blocksPerCluster: 64
clusterCount: 60342
fatStartBlock: 136
fatCount: 2
blocksPerFat: 236
rootDirStart: 608
dataStartBlock: 640

Any suggestions?

Are you using fileloggerdemo?

I got the fileloggerdemo working. I changed:

result = FileLogger::append("data.log", buffer, length);

to:

result = FileLogger::append("data.[glow]txt[/glow]", buffer, length);

On my PC, fileloggerdemo loads as a notepad text page; my PC is using Windows Vista. On the sd card, create a file named data, allow the notepad software to add [u].txt[/u].

Filelogger woks ok, it adds data to the end of the sd file and does not over write previously recorded data. However, I just started working with it, and cannot get data on the card other than in ascii code unless data is added as text to the array called 'buffer'. There's a bit of confusion with that part.

Have you tried MMC/uFat2 and Deviceprint at this location (SD/MMC From the ground up)>(http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235125412) Problem with that system is that previously recorded data is overwritten if you stop and restart.

Yes, I use fileloggerdemo. I tried various filenames, the filename on the card matching the one in the code. But the fail initializing error remains. I suppose it has to do with the clock speed being to high.

I have used the libelium MicroSD module with my arduino before.

Let me go fish it out and have a fiddle

Mowcius

I just tried my libelium microSD module through the ICSP header on my duemilanove, using the basic SDuFAT library and it seemed to work fine.

So yours does not work with the basic library?

Mowcius

No. With SD_uFAT_basic I get errors:

[hola.txt] - file info
[hola.txt] - ..error!

[hola.txt] - add text
alskdjflkdsajf.
[hola.txt] - add string
[hola.txt] - ..done

[hola.txt] - file content
[hola.txt] - ..error!

The file hola.txt is there on the card, created with vim, containing 512 spaces. The libelium SDmicro module is on the ICSP, power jumper set to 3V3 and GND. Digital pins 1-7 are in use by a LCD and a temperature sensor DS18B20, analog 5 by a thermistor. I made no changes to the code in SD_uFAT_basic.

Hmm, I will try to take a look at that when I have a bit more time, have you tried a different card/different formatting?

Mowcius

Gents, I had the same issue witzh that bloody SD card thing !>:( See my thread on http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261141357

Finally filelogger worked, but stopped recording after reaching a certain limit of characters saved. I need a datalogger with a least 65000 lines each 50 characters in and no system could do that. Now I bought Openlog (http://www.sparkfun.com/commerce/product_info.php?products_id=9530) . I received this with an old firmware level and need to upgrade it. I hope this works as it records the serial port as a dedicated and separated system...

I do not want to demotivate me :-[. If you get it running I would be happy!

The reason why the SD card would not record more then 18 1/2 lines (from the other thread) will be that with SDuFAT, you need to have a file full of the amount of characters you require in spaces. If you need 4 lines then you will need, the starting character, 4 lines of spaces and then i’m not sure if you need an ending character…

Mowcius

Hey unit, I ´d like to do the exactly same thing like you. Unfortunately my Sd-Shield and DS18B20 sensors are still on their way. Lets stay in touch about the projects. I will write as soon as I get some results (good or bad ;) Keep goin´ Jean

Ok, now the stuff described one post further ist there. I got one DS18B20 to work and stored the data in the Internal EEPROM just to see if it is working. Fine. Now i´m stuck with this SDCard Thing. I have the following Setup:

  • Arduino Duemilanove
  • Arduino 0017 on MacOSX 10.5.5
  • Libelium MicroSD Module on Pins 8,9,10,11,12,13,GND
  • Transcend MicroSD Card, FAT formatted (with MacOSX)
  • hola.txt created with Vim and stored on MicroSDCard

I tried Filelogger and the SDuFAT librarys but nothing works. The Code compiles well and is sent to the 328. It reacts on my commands ober the serial port but all i get are error Messages.

For Example: With SD_uFAT_basic from the SDuFAT libraries i get these Error Messages: If i send "H" it says: H help L file info D delete P append string W init file and write R dump to serial A append text

Thats alright. But if i try some of the commands it gives me the answers like that: For "L": [hola.txt] - file info [hola.txt] - ..error! For "P": [hola.txt] - add string [hola.txt] - add string [hola.txt] - ..done

But: theres no change at all to the Textfile :(

The strange thing is: if I remove the microSD-module or only the MicroSDCard and try "P" it says:

[hola.txt] - add string [hola.txt] - add string [hola.txt] - ..error!

So there is at least a difference between the setup with and without shield/card....

But why is Arduino not writing to the File?? Should i try to format the Card under WinXP (Mac OS only can format to "FAT", WinXP can format to FAT16 or FAT32) I created the .txt file with "Vim" in the Terminal-Application under MacOSX, i think this should be a very "clean/basic" .txt file.

mowcius: can you post the setup an code you were using? Is anybody succesful working with the Module??

mowcius: can you post the setup an code you were using?

Sure thing.

I am using the standard code:

#include "SDuFAT.h"

// define the pin that powers up the SD card
#define MEM_PW 8

// help string to be sent to the serial port
#define HELP "H help\nL file info\nD delete\nP append string\nW init file and write\nR dump to serial\nA append text\n"

// variable used when reading from serial
byte inSerByte = 0;

void setup(void)
{
  // on my MicroSD Module the power comes from a digital pin
  // I activate it at all times
  pinMode(MEM_PW, OUTPUT);
  digitalWrite(MEM_PW, HIGH);
  
  // configure the serial port to command the card and read data
  Serial.begin(19200);
}

void loop(void)
{
  // Arduino expects one of a series of one-byte commands
  // you can get some help by sending an 'H' over the serial port
  if (Serial.available() > 0) {
    int result = 0;
    inSerByte = Serial.read();
    switch (inSerByte) {
    case 'H':
      Serial.println(HELP);
      result = 3; // special output for help message
      break;
    case 'L':
      result = SD.ls("hola.txt");
      break;
    case 'R':
      result = SD.cat("hola.txt");
      break;
    case 'W':
      result = SD.write("hola.txt");
      break;
    case 'A':
      result = SD.append("hola.txt");
      break;
    case 'P':
      result = SD.println("hola.txt","\nhola caracola");
      break;
    case 'D':
      result = SD.del("hola.txt");
      break;
    default:
      result = 2; // value for unknown operation
      break;
    }
    
    // print a status message for the last issued command
    // for help (result == 3) won't print anything
    if (result == 1) SD.printEvent(ERROR, "hola.txt");
    else if (result == 2) SD.printEvent(WARNING, "unknown command");
    else if (result == 0) SD.printEvent(SUCCESS, "hola.txt");
  }
}

I am using the jumper on 5v with the module connected to the digital pins however it also works if I change to ICSP and switch the jumper (no change to code).

I am using a 2GB microSD card (unbranded -the one I got with it) but it works with all my SanDisk cards too. This one is FAT formatted using standard windows XP formatting.

On the card I have hola.txt with 25 [ETX] characters however it seems to work with any number of the characters or just one at the end and the rest as spaces. I can see the [ETX] characters using notepad++, in notepad they come up as boxes (unknown characters).

Hope that helps,

Any more questions? Go ahead! ;)

Mowcius

YEEEHAAAA!

mowcius,

  1. that answer was quick!
  2. it works!

I tried exactly as you described. I´m now using Notepad++ under WinXP and everything is just fine!

I dont know exactly what the problem was, but there could have been 2 critical points:

1st: If you format the card under OSX, the formatting is FAT32 (seen under Windows (OSX just calls it "FAT" and there are no other options to choose when formatting the card)

-> one has to format the card under windows (choosing "FAT")!

2nd: the damn "ETX" character! I did´nt figure out how to write it directly to the textfile in Notepad++, so i wrote a file full with "" (which is the "ETX" character in html), saved it as etx1.html, opened etx1.html in my browser and copy- and pasted the "ETX" characters to my "hola.txt" in notepad++.

I hope one can understand how i did it.

I think its ok to just fill up the "hola.txt" with "ETX" Characters.

Now the building can go on. I will finish the project and make a documentation and link it here as soon as i have passed my coming exams.

big thx mowcius!

Jean Herbes

big thx mowcius!

Glad it worked for you :slight_smile:

Mowcius

Ok, i got a bit spare time and tried to store the data read from the DS18B20 on the Card,

i know exactly where my problem is :smiley:

i can only store “strings” to the Sd-Card, and i only get “floats” from the sensors, so i have to convert float to string…
appearantly this isnt as easy as i thought. I´m searching now for over 3h to find a way to convert this. I found many links and big code snippets and people saying it works for them…but i can´t get it to work…

Maybe one of you knows a simple way to convert the floats one gets from the sensors to strings one can save to card…

I will post my code just in case somebody wants to watch the problem.
The conversion should take place just after the reading from the sensors in the “printTemperature” function

#include <OneWire.h>
#include <DallasTemperature.h>
#include "SDuFAT.h"

// Data wire is plugged into port 7 on the Arduino
#define ONE_WIRE_BUS 7

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

// variable used when reading from serial
byte inSerByte = 0;

void setup(void)
{
  // start serial port
  Serial.begin(9600);

  // locate devices on the bus
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  
  // assign address manually.  the addresses below will beed to be changed
  // to valid device addresses on your bus.  device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };

  // Method 1:
  // search for devices on the bus and assign based on an index.  ideally,
  // you would do this to initially discover addresses on the bus and then 
  // use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 12);
 
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  
  // get the temperature
  float tempC = sensors.getTempC(deviceAddress);
  
  
  
 //floatToString conversion here!!!!
  
  
  SD.print("hola.txt",  );
  
  delay(5000);            //delay because of delay ;)
  
 }

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  // It responds almost immediately. Let's print out the data
  printTemperature(insideThermometer); // Use a simple function to print out the data
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
    
    
  }
}

There have to be 100 people out there having the same problem :wink:
Am i the only one not being able to fix this? :slight_smile:

Greetings

Jean

I found this on these forums a wee while ago. The link to the original post is in the comment. Works just fine. Kudos to the person who wrote it.

/* If this works be sure to save it !!!!!!!! */
// It does and this is the guy who wrote it
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1164927646/8#8
///////////////////////////
char *ftoa(char *a, double f, int precision) {
  long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
  
  char *ret = a;
  long heiltal = (long)f;
  itoa(heiltal, a, 10);
  while (*a != '\0') a++;
  *a++ = '.';
  long desimal = abs((long)((f - heiltal) * p[precision]));
  itoa(desimal, a, 10);
  return ret;
}

I am now having the same problem so you are not alone.

I got the lib board and tried the hola.txt and it failed.

However I also just loaded up LIB16 and tried both SDinfo and Analoglogger examples. Both produce init error , error 1

I have the card formatted with fat16 on windows.

Art

Ok, finally i figured out how to use the ftoa function. Here is my code to read temperature data from one DB18B20 and to store it on the SD-Card in the libelium module. It worked once (with a 15mb hola.txt filled up with ETX caracters…don´t ask) and after i tried it with a normal hola.txt it wont work again. I´m sure the code works so it has something to do with this bloody hola.txt/ETX/libelium thing. I will abandon this buggy module an try to get this thing working on an S65 shield…
Anyway, here ist my code. I hope the comments are useful.

Greetings,
Jean

#include <OneWire.h>
#include <DallasTemperature.h>
#include "SDuFAT.h"

// Data wire is plugged into port 7 on the Arduino
#define ONE_WIRE_BUS 7

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

// variable used when reading from serial
byte inSerByte = 0;

void setup(void) 
{
  // start serial port
  Serial.begin(9600);

  // locate devices on the bus
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  
  // assign address manually.  the addresses below will beed to be changed
  // to valid device addresses on your bus.  device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };

  // Method 1:
  // search for devices on the bus and assign based on an index.  ideally,
  // you would do this to initially discover addresses on the bus and then 
  // use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 10);
 
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

}


// function to print a device address
void printAddress(DeviceAddress deviceAddress) 
  {
    for (uint8_t i = 0; i < 8; i++)
    {
      if (deviceAddress[i] < 16) Serial.print("0");
      Serial.print(deviceAddress[i], HEX);   
    }
  }


// function to print the temperature for a device to serial
void printTemperature(DeviceAddress deviceAddress)
  {

    float tempC = sensors.getTempC(deviceAddress);
    Serial.print("Temp C: ");
    Serial.println(tempC);
    //Serial.print(" Temp F: ");
    //Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
  }

 
// function to store temp-data on the card
void saveTemperature(DeviceAddress deviceAddress)
  {
    
    char float_conv[10];                                    // array to hold the data for the ftoa fuction
    float temp1 = sensors.getTempC(deviceAddress);          // variable to store temperature before converting
    SD.println("hola.txt", ftoa(float_conv, temp1, 2));    // saving the directly converted temp1 to card 
  }
  
// function to convert the temperature (given in float) to a string 
// (http://www.arduino.cc/cgi-bin/yabb
/YaBB.pl?num=1164927646)
char *ftoa(char *a, double f, int precision)
  {
    long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
    char *ret = a;
    long heiltal = (long)f;
    itoa(heiltal, a, 10);
    while (*a != '\0') a++;
    *a++ = '.';
    long desimal = abs((long)((f - heiltal) * p[precision]));
    itoa(desimal, a, 10);
    return ret;
  }



void loop(void) {
  
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  //Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  //Serial.println("Done");
  // It responds almost immediately. Let's print out the data
  
  printTemperature(insideThermometer); // Use a simple function to print out the data
  delay(100);
  saveTemperature(insideThermometer); // use the above created function to save the data to the card
  delay(4900);            //delay because of delay 
}

Quote “Only SdFat works. I got it to work by changing card.init = (true) in the SdFatInfo code. So I assume all my other failures have to do something with the Libelium board being accessed at 8 MHz, which seems to be too fast.”

I have been struggling with the Arduino Mega and just about every SD card library for over a week, until I tried your hack. The SdFatInfo example worked perfectly, so I though, why not do the same to all other examples. It turns out that the TRUE or 1 is an argument for the function Sd2Card::init(uint8_t slow), so if slow is true, the code runs just fine. I checked deeper into the function, and pretty much the only time this argument is used is in this statement:

// if !slow set SPI frequency to f_OSC/2
if (!slow) SPSR |= (1 << SPI2X);

apparently it has to do with the clock frequency for the SPI interface, so I choose to remain ignorant and comment out this line to:

// if !slow set SPI frequency to f_OSC/2
if (!slow) SPSR |= (1 << SPI2X);

And, voila, every example now works like a charm. I don’t know yet if this will come around and bite me, so if anyone can come up with a better way to explain this, i’d greatly appreciate it.

figassis

Hi all,

I’m having a somewhat related issue using OneWire for DS18B20 temperature sensors no longer working once I create / open a file with an SPI communication routine to my uSD card.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1270923978

I am not using the Libeium microSD module, however. I am using Sparkfun’s shield DEV-09520, which is essentially a direct connection between the pins and the SD card. From what I’ve read about this card being out of spec, I would not recommend it. Also, it is extremely sensitive to type of connector – only the long legged stackable headers (e.g. Sparkfun’s PRT-09280) would work. I could use other connectors and light up LED’s no problem, but I could not get a communication signal through them.

I just received a different microSD BOB from Gravitech. Now that I found the stackable headers cured the issue with the Sparkfun boards (on both a Mega 1280 and a Duem 328) for their uSD board, I’ll probably wait to try it.

I just need to keep the Temperature Sensors working!