SD/MMC From the ground up

@packrat -

You've got it then. The deviceprint demo needs a file called "data.txt" - it can be nothing else.

With your SD plugged into you computer, just open up notepad (assuming windows), and make a file consiting entirely of the letter "B" or something. Keep copy-n-pasting big blocks of the letter B. Save teh file to the card with the filename "data.txt". Check the size of the file in explorer - it should be AT LEAST 1k. Eject the card and put it in the arduino card holder.

Run the device print demo. Open the serial monitor in the arduino IDE. When the "done" message appears, take the card out of the arduino and put it back into the computer. Open the file - there should be a long list of timestamps.

The bigger you intially make the file, the longer it will keep writing. It will keep going until there is less than 512bytes left IN THE FILE, the remaining bytes will be unchanged from whatever you filled it with initially (B=blank in my head).

Thank you,Ttrialex.

I got that to work. I put in about 15k of data, and got back time stamps up to approx 29450. I guess that means about 30 seconds of writing. That made me happy.

Now if I can just figure out how to enter data, collected from an exterior source, to the card using the arduino. By that I mean, entering data on one of the arduino pins, binary 3 for instance, then have that data relayed to and entered into the SD card.
I'll be much happier if I can get that to happen.

Does the uFat example have anything to do with entering data?
The uFat example gives this result: "1 files found.", "data.bin not present on card."

Much thanks for the help

@packrat

How much arduino or avr experience do you have? just out of interest, because sometimes it is easier to help someone when you know what they can or can't understand.

Anyway the deviceprint demo file really does show you a lot, it is an excellent example. Look for these two lines

    dp.print_P(PSTR("Time is now: "));
    dp.println(millis(), DEC);

So the first line shows you how to send a string to be saved to the card. The second line shows you how to log a variable, and go to a new line.

So you could write something like

dp.println(analogRead(0), DEC);

and it would log the value on analog pin 0.

Posted by: trialex Posted on: Yesterday at 22:55:01
@packrat

How much arduino or avr experience do you have? just out of interest, because sometimes it is easier to help someone when you know what they can or can't understand

.

I'm very new at it, but I have managed to put together a couple of sketches that are somewhat above Blink, but much less complicated than this one. Borrowing from arduino's playground, I put together sketches from which I can enter external data to an arduino, save the data to external eeprom, then read it back using a seperate arduino board. Not real complicated, and rather crude, I'm sure.

These SD sketches are rather complicated for me, since some of the commands aren't even listed in Arduino's Reference file, and the tutorial was obviousloy written for those that have had quite a lot of experience with, not only arduino, but with microconntrollers, programming and computer science in general. There are many terms in the tutorial that I had bever heard of, which were apparenty from old time computerese, much of it being terms that the reader "should already know" Some of the nomenclature would make an army manual read like "Richard and Jane".

However, I will thank you for this last bit of information. I had pretty much come to that conclusion myself. If it works that will be great, if not, I will go back to plan 'A.67', which will be just using the eeprom, for data logging. I don't plan on going much further than that.

Some other time.

Looks like I got back just in time! Don't Jump!!

Unfortunately you can't pick up a violin and instantly play like Yehudi Mehuhin. If programming was easy I'd be out of a job...
;D

I'm sorry to hear you're having a hard time with this. I think if you just keep plugging away all those strange sounding terms will become familiar and slot into some order. It won't happen overnight but it's like building a lot of little bridges, you need the keystones in place to get any further.

You should be able to get from my demo app to a fully fledged data logger in very few steps. Would it help if I provided a new sketch which did the grunt work leaving only the bits needed to gather the data?

sirmorris asks:
Would it help if I provided a new sketch which did the grunt work leaving only the bits needed to gather the data?

No, I'd rather that you didn't; I think it would be unfair of me to ask you to do that.

I needed to know where, on a board and in the sketch, to inject electronic pulses so that they could be counted, timed, then have that data saved in a transportable memory chip or card. Mr trialex helped me with that. So, I think I can take it from this point.(I hope)

In another sketch I used "attachInterrupt()" to allow pulses to be fed to the board at pin3, and "millis()" plus other needed code to time and count the pulses, then used code , which I found in arduino's playground, to send, and receive, the resulting data to, and from, external EEPROM. I kinda thought maybe I could do something similar with your (sirmorris's) "SD/MMC from the ground up" coding.

Using an SD card to save data collected from Harley's speed sensor, by an arduino board, I should be able to leave the board attached to the bike, and, after a test run, remove the card only, grasp the card between forefinger and thumb, run to my computer and enter the data, which I almost killed myself to collect, directly into the PC by use of USB port. I have high hopes for this sketch.

By the way, part of my confusion resulted from the suggestion that both Ufat2 example and DevicePrint demo be downloaded. (Maybe you didn't suggest that both be downloaded.) Anyway, I got the impression that both were necessary, and I guess that's not the case. :-/

I'm not sure if I've ever heard music by that fiddler you mentioned, but old Eric Clapton is a dang good git-tar picker. :slight_smile:

sláinte (on St. Paddy's day)

This should help. please bear in mind it's fresh off my fingertips and I haven't had a chance to try it out.. :o

I think it kind-of does what you need.. you should develop the interrupt pulse counter and get that all working printing its results to the serial port, then transplant the counting code into here. Add the stop button and you're good to go.

// !! use the device print demo, and delete the setup & main from it
// !! replacing it with what you see here.


 // or whatever
#define STOP_PIN 3

void setup(void)
{
  Serial.begin(115200);

  // some users have reported cards which won't initialise 1st time
  //
  int n = 0;
  while (mmc::initialize() != RES_OK)
  {
    if (++n == 10)
    {
      error_P(PSTR("Couldn't initialise card"));
    }
    delay(500);
  }

  if (!microfat2::initialize(sectorBuffer, &mmc::readSectors))
  {
    error_P(PSTR("Couldn't initialise microfat"));
  }

  // find the start sector and length of the data we'll be overwriting

  unsigned long sector, fileSize;

  if(!microfat2::locateFileStart(PSTR("DATA    TXT"), sector, fileSize))
  {
    error_P(PSTR("Couldn't find data.txt on the card"));
  }
  
  // The dp library won't write past the end of the allowed space.
  // Indeed, it will only write up to the nearest sector boundary at
  // the end of the file on the card. If your target file is 1000 bytes,
  // only 512 will be written over. The remaining will be left as they
  // were when written to the card.

  dp.initialize(sector, fileSize / 512, sectorBuffer, proxyWriter);
  
  memset(sectorBuffer, '.', 512);

  // get pulses
  //
  attachInterrupt(0, interruptHandler, RISING);

  // make the stop button pin an input, and set it's pull-up resistor
  // the switch should be push-to-make, and connect the pin to ground.
  //
  pinMode(STOP_PIN,INPUT);
  digitalWrite(STOP_PIN,HIGH);

  print_P(PSTR("All initialised OK!\nWriting..."));
}



// this variable is set by the interrrupt routine once a second.
//
// the volatile keyword instructs the compiler that the value
// can change at any time, and should therefore not be cached
// or otherwise involved in optimisations.
//
volatile int counts;

// this variable gets set to true by the interrupt routine when
// a second has elapsed and the count is ready. it's set to false
// by the main loop when the data has been written to the card.
//
volatile bool dataIsAvailable = false;


// every time the sensor pulses low to high, we get called here.
// static variables retain the value they're given between calls.
//
void interruptHandler()
{
  static int ct = 0;
  static long lastMillis = millis();

  ++ct;

  long now = millis();
  if(now - lastMillis > 1000)
  {
    ct = 0;
    counts = ct;
    lastMillis = now;
    dataIsAvailable = true;
  }
}


void loop(void)
{
  if(dataIsAvailable && dp.m_sectorsAvailable > 0)
  {
    // reset the flag variable so we don't keep writing the vale over and over...
    // put the count value into the file. we don't _need_ to flush here, but it
    // will ensure that we don't lose any values as we can stop logging at any time.
    //
    dataIsAvailable = false;
    dp.println(counts, DEC);
    dp.flush();
  }

  // attach a button to some pin and define this variable to let the compiler
  // know which one it's on :)
  //
  if(digitalRead(STOP_PIN)==LOW)
  {
    // switch on the on-board LED to say that the sketch is stopped
    digitalWrite(13,HIGH);

    for(;;) // ever
    {
      // this simply stops the sketch dead, so the card can be removed.
    }
  }
}

Charlie

Thanks, sirmorris, you needn't have done all that, and I appreciate it.

I will give it a try, or "give it a bit of a go" as they say in those old English movies.

Hehe you're welcome! I hope the hog appreciates all this attention :wink:

Posted by: sirmorris Posted on: Yesterday at 00:01:38
This should help. please bear in mind it's fresh off my fingertips and I haven't had a chance to try it out..

I really hate to bother you again, but my first attemts at using your most recent code of 3/17/09, results in the following:

o.In 'function interrupt handler()':
C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_acquire'
C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_release'

Couldn't determine program size:
C:\Users\Owner\arduino-0014\hardware/tools/avr/bin/avr-size:
'C:\Users\Owner\AppData\Local\Temp\build22823.tmp\sketch_"sketchname".hex':No such file

I left the name of the sketch as the automatic name that appears, which was '090319b'.
I have 3-ms*(pos)*, 5v, square wave multivibrator pulses fed into arduino digital pin2, which corresponds to "attachInterrupt(0,interruptHandler,RISING);, approx. line 109

And Idid as follows:

// !! use the device print demo, and delete the setup & main from it
// !! replacing it with what you see here.

Which was to put in the new code

Sorry to be such a pest
Thank you for your help

Hi

I've an old memory stick, see here some pictures
Do you think i can use this one, like an sd card used by uFat or Roland Riegel lib ?
Do you know how pins are numbered ?

Hi there.

No, this is a completely different standard to MMC. Sorry! :-[

I have also a memory stick Pro Sandisk
Pins are in the other side, just like an MMC card

You think also it's not compatible with uFat or Roland Riegel lib ?

Posted by: sirmorris Posted on: Yesterday at 00:01:38
This should help. please bear in mind it's fresh off my fingertips and I haven't had a chance to try it out..

I've acheived partial success by not using the 'interrupt handler()', using some of the handlers commands directly in the void loop, and some of the timing commands that I used to save data to external EEPROM (also in the void loop).

Partial success, I say. I get proper pulse counts/second transferred to the SD card along with the millis() time stamp. But there is a mixup in the card, data starts to be written for a short while, then a gap of a few seconds when data starts to be recorded again, and millis() starts up at a point showing several seconds later.

I shall struggle on

Pakrat :slight_smile:

Apparently, arduino doesn't like static variables being declared in "void setup(void)", but it allows them to be declared at the beginning of a sketch*(the declarations section)*, then are allowed to be used as such later in the sketch.

When I tried declaring a static in "void setup", I got these error messages:
]C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_acquire'
C:\Users\Owner\AppData\Local\Temp\build22823.tmp/Temporary_6346_5538:150:undefined reference to '__cxa_guard_release'

When I declared them (static vars) at the start of the sketch, they worked OK.
I'm still working at my SD card data logger, and its coming along alright. If I leave the timing, counting,etc in "void setup(void)", I get one shot at storing the data on the card, until it fills the pre-stored "data.txt" area. The amount of time it takes to fill the area depends on the amount of pre-stored data, and the amount of new data being shoved on the card. (it takes about 38 ms between writings to the card)

When I move the timing, counting procedure to the "void loop" section of the sketch, I get strange results with occasional large gaps in the data.

pakrat

Hi

I've read the thread, but I'm not sure where to retrieve this lib...
Maybe at Arduino Nut: Say Hello to uFat2 ?

It's the last version of the lib ? because there are compilation errors
They are due to <wprogram.h> and <wconstants.h>

I had to change in fact to <WProgram.h> and <WConstants.h>

Is it possible to apply these changes and put this lib officially in arduino wiki, if it used by many persons ?

Cheers

Hi. Yes, this is the latest version of the lib. The latest code will always be linked from ArduinoNut. As for the compilation errors - they only occur in older IDEs. Are you sure you read the thread from the beginning?? :wink:

This library uses the newly-abstracted Print class available in Arduino-0012 and above.

Update your IDE and all will be good. You can keep the different versions side-by-side so you won't lose anything.

I use Arduino IDE0013 for linux, which is the last version for linux

and wconstants.h and wprogram.h have been replaced, I imagine, by WConstants.h & WProgram.h

Ahaaa.. I smell case sensitivity?

I'll amend these straight away. Thanks for pointing it out :slight_smile:

Yes linux is case sensitive :slight_smile:
Thanks for the correction

Another thing on your lib, with initial SPI settings, SPI runs at 125KHz (for a 16MHz crystal), right ?

Do you increase this speed after the initialization ?

Because in fact SD specs says that after initialization, frequencies up to 25MHz can be used

I would be interested about the tests you may have done to increase the speed (i've seen the commented line: SPSR = _BV(SPI2X)).
Maybe you've tried, and you've had some trouble ?