Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Safely ejecting SD card (and other problems)

sd uSd datacard datalogging

  • Please log in to reply
36 replies to this topic

#1 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 11 February 2013 - 08:41 PM

Hi all,

 

I'm having a number of problems with my NP2 (latest firmware, VS2012) and SD logging. To start, here's one piece of code:

 

using (var fileStream = new FileStream(@"SDtest.txt" , FileMode.Create))            {                StreamWriter fWrite = new StreamWriter(fileStream);                fWrite.WriteLine("Testing...derp derp derp");                fWrite.Close();            }

 

First of all, if I upload this to the board, nothing runs, and I get "An unhandled exception of type 'System.IO.IOException' occured in System.IO.dll." Should I just use a try/catch block to handle this when there isn't an SD card? I just did that and that seems to work, but is there a better way, like making sure there's an SD card to begin with without throwing any exceptions?

 

My other problem: Suppose I power on/reset the NP2 with an SD card inserted. The code runs fine, however, when removing the SD card, it corrupts. Sometimes my PC will tell me that the card needs to be scanned and fixed. Other times it will show me the test.txt file in the directory, but when i try to read it I'm told the file is corrupted and unreadable. How do I safely eject my SD card so I can retrieve data later?

 

I'm using a 2GB card formatted as FAT.

 

EDIT: Another problem is that if I insert a card while the NP2 is running, it will hang. Also, if I try to upload new code, I get the whole "Error while deploying, Continue?" with "An error has occurred. Please check your hardware". It takes a power cycle to allow me to upload new code.



#2 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 12 February 2013 - 06:38 AM

As I understand there's a pin on sd card slot (called CI = "card inserted" or something like that) that changes when a card is inserted. You should be able to read this pin before attempting to mount the card. I even think there's such a bin defined among the others of the Cpu.Pins enumerator.



#3 NooM

NooM

    Advanced Member

  • Members
  • PipPipPip
  • 490 posts
  • LocationAustria

Posted 12 February 2013 - 07:01 AM

you do not use Cpu.Pins for netduino -.-

 

netduino has the card detect implemented, and it even throws an interrupt when you enter a card (maybe, i guess) also when you remove it.



#4 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 12 February 2013 - 10:51 AM

I guess you meant to say that the Cpu.Pins enumerator is not used for the card detect pin, rather it's a built in function?

 

That only goes for boards with a built in SD card slot like the N+ and N+2 and not for Netduino boards in general.

 

I use the mini mostly and have to wire the card detect pin explicitly. How else would the board know whether a card is inserted or not?



#5 NooM

NooM

    Advanced Member

  • Members
  • PipPipPip
  • 490 posts
  • LocationAustria

Posted 12 February 2013 - 12:58 PM

first: yes thats only for the plus and plus2.

than: i meant its not Cpu.Pins its just Pins enum.

 

also, since this is in the plus/plus2 part of the board, i was talking about that.



#6 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 12 February 2013 - 01:44 PM

Ok, thanks for carifying that.



#7 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 13 February 2013 - 12:19 AM

you do not use Cpu.Pins for netduino -.-

 

netduino has the card detect implemented, and it even throws an interrupt when you enter a card (maybe, i guess) also when you remove it.

So how does that help with my various errors?



#8 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 13 February 2013 - 05:59 AM

Well, it enables you to detect whether a card is inserted or not before attempting to mount or access the card. As I understand, this should help you in resolving all three problems you're experiencing or at least the last two.

#9 NooM

NooM

    Advanced Member

  • Members
  • PipPipPip
  • 490 posts
  • LocationAustria

Posted 13 February 2013 - 09:47 AM

So how does that help with my various errors?

 

it gives you some knowledge :P

 

since hanzibal allready told you about the card-detect pin ...

 

the try/catch approach you mentioned may work, but i think its better to

check if a sd card is in (set a boolean with the card-detect event, maybe there is allready one?)

and only write data when its actually in.



#10 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 13 February 2013 - 07:44 PM

it gives you some knowledge :P

 

since hanzibal allready told you about the card-detect pin ...

 

the try/catch approach you mentioned may work, but i think its better to

check if a sd card is in (set a boolean with the card-detect event, maybe there is allready one?)

and only write data when its actually in.

There isn't anything card-related in the Pins enum. Just all the GPIO stuff. What about the RemovableMedia class?

 

I still can't write a file that isn't corrupted. It still crashes my board when I insert/remove cards while it's running.

 

Alright, here's my code:

 

using System;using System.Net;using System.Net.Sockets;using System.Threading;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware;using SecretLabs.NETMF.Hardware.Netduino;using System.IO;using System.IO.Ports;using System.Text;using Microsoft.SPOT.IO;using SecretLabs.NETMF.IO;namespace SPI_ADC{    public class Program    {        public static SerialPort talkback = new SerialPort("COM2", 14400, Parity.None, 8, StopBits.One);        public static OutputPort confirm = new OutputPort(Pins.ONBOARD_LED, false);        public static PWM variableRed = new PWM(PWMChannels.PWM_PIN_D5, 1000, 0, false);        public static Random cycle = new Random();        public static bool cardInserted = false;                public static void Main()        {            RemovableMedia.Insert += new InsertEventHandler(SD_Insert);            RemovableMedia.Eject += new EjectEventHandler(SD_Eject);            confirm.Write(true);            if (cardInserted)            {                RGB.Green();            }            else            {                RGB.Red();            }            Thread.Sleep(250);            confirm.Write(false);            AD7714.Init();            //LCD.Init();            int rejected = 0;            int samples = 20;            int g1 = 1; ///gains can be powers of two, from 1 to 128 inclusive. Otherwise it will default to 1. Work on feedback for this.            int g2 = 1;            int g3 = 1;            int g4 = 1;            int g5 = 1;            while (true) // ERMAHGERD LERP            {                #region acquisition                variableRed.Stop();                variableRed.DutyCycle = cycle.NextDouble();                variableRed.Start();                Thread.Sleep(50);                long intONE = AD7714.ReadChannel(1, samples, g1);                long intTWO = AD7714.ReadChannel(2, samples, g2);                long intTHREE = AD7714.ReadChannel(3, samples, g3);                long intFOUR = AD7714.ReadChannel(4, samples, g4);                long intFIVE = AD7714.ReadChannel(5, samples, g5);                double vONE = (((double)intONE * 3.0) / (g1 * 16777215.0));                double vTWO = (((double)intTWO * 3.0) / (g2 * 16777215.0));                double vTHREE = (((double)intTHREE * 3.0) / (g3 * 16777215.0));                double vFOUR = (((double)intFOUR * 3.0) / (g4 * 16777215.0));                double vFIVE = (((double)intFIVE * 3.0) / (g5 * 16777215.0));                if (intONE == 8388608 || intTWO == 8388608 || intTHREE == 8388608 || intFOUR == 8388608 || intFIVE == 8388608)                {                    rejected++;                }                                #endregion                #region output                Debug.Print("CHANNEL ONE:   integrated reading = " + intONE.ToString() + " = " + vONE.ToString("F4") + "V");                Debug.Print("CHANNEL TWO:   integrated reading = " + intTWO.ToString() + " = " + vTWO.ToString("F4") + "V");                Debug.Print("CHANNEL THREE: integrated reading = " + intTHREE.ToString() + " = " + vTHREE.ToString("F4") + "V");                Debug.Print("CHANNEL FOUR:  integrated reading = " + intFOUR.ToString() + " = " + vFOUR.ToString("F4") + "V");                Debug.Print("CHANNEL FIVE:  integrated reading = " + intFIVE.ToString() + " = " + vFIVE.ToString("F4") + "V");                Debug.Print(rejected.ToString() + " error readings so far.");                Debug.Print(" ");                LCD.Open();                LCD.Clear();                LCD.Print("1:" + vONE.ToString("F3") + " 2:" + vTWO.ToString("F3"));                LCD.Position(1, 0);                LCD.Print("3:" + vTHREE.ToString("F3") + " 4:" + vFOUR.ToString("F3"));                LCD.Close();                string counts = intONE.ToString() + "Z" + intTWO.ToString() + "Z" + intTHREE.ToString() + "Z" + intFOUR.ToString() + "Z" + intFIVE.ToString() + "B";                string gains = g1.ToString() + "Z" + g2.ToString() + "Z" + g3.ToString() + "Z" + g4.ToString() + "Z" + g5.ToString() + "B";                string voltages = vONE.ToString("F4") + "Z" + vTWO.ToString("F4") + "Z" + vTHREE.ToString("F4") + "Z" + vFOUR.ToString("F4") + "Z" + vFIVE.ToString("F4") + "B";                string errors = rejected.ToString() + "END";                string message = counts + gains + voltages + errors;                byte[] xmit = Encoding.UTF8.GetBytes(message);                talkback.Open();                talkback.Write(xmit, 0, xmit.Length);                talkback.Close();                if (cardInserted)                {                    try                    {                        using (var fileStream = new FileStream(@"SDtest.txt", FileMode.Append, FileAccess.Write))                        {                            StreamWriter fWrite = new StreamWriter(fileStream);                            fWrite.WriteLine("Testing...derp derp derp");                            fWrite.Close();                        }                    }                    catch (Exception ex)                    {                        Debug.Print(ex.Message);                    }                }                #endregion                RGB.Blue();                AD7714.Init();                Thread.Sleep(1000);                if (cardInserted)                {                    RGB.Green();                }                else                {                    RGB.Red();                }            }        }        static void SD_Insert(object sender, MediaEventArgs args)        {            RGB.Green();            cardInserted = true;                    }        static void SD_Eject(object sender, MediaEventArgs args)        {            RGB.Red();            cardInserted = false;        }    }

 

There are a number of additional classes that manage sensors. Don't worry so much about the RGB.Whatever(), that's only there to help me manage feedback with an RGB LED. 

 

When I insert the card, the program keeps running just fine. When I remove the card, it hangs a little before the SE_Eject event triggers. Maybe 3-5 seconds. Normal operation then resumes.

 

When I insert the card into my computer, I'm asked to scan and recover the card, since it has problems. The output from that is:

 

 

test.txt first allocation unit is not valid. The entry will be truncated.Removing trailing folder entries from  

What do?

 

EDIT: When I use my computer to create a nonempty file on the card named test.txt and then try to operate the Netduino program normally, it works. It writes lines to the text file and inserts/ejects without problem. This seems like a hassle to do every time (I'll be doing a lot of data acquisition) and there ought to be a better way.



#11 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 13 February 2013 - 11:11 PM

If I'm not mistaken, you start off by assuming the card is not present by initializing the variable to false. Isn't there a way of getting actual state using some method of the RemovableMedia class? If not you could use the try/catch pattern and set the variable accordingly. If the card is present at startup, you'd have to cycle it for anything to get written. Correctt? As for the card getting corrupted, I don't really have any suggestions but if you eject the card in the middle of a write operation it surely could get corrupted since the file allocation table might not be correctly set. Now, I doubt the CLR uses lazy writes on SD but you could try and do a flush before closing the stream writer.

#12 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 13 February 2013 - 11:19 PM

If I'm not mistaken, you start off by assuming the card is not present by initializing the variable to false. Isn't there a way of getting actual state using some method of the RemovableMedia class? If the card is present at startup, you'd have to cycle it for anything to get written. Correctt? As for the card getting corrupted, I don't really have any suggestions but if you eject the card in the middle of a write operation it would probably be corrupted since the file allocation table might not be correctly set. I doubt the CLR uses lazy writes on SD but you could try and do a flush before closing the stream writer.

The only members of RemoveableMedia are Eject, Insert, Equals, and ReferenceEquals.

 

There is a SecretLabs.NETMF.IO.StorageDevice class, but I wouldn't know where to begin to find the documentation for it. It has SDMount/Unmount members, though.

 

Yes, if the card is present at powerup or reset, it gets correctly written to, provided there is a nonempty file already on it.

 

The event handler for card inserted gets called at startup if the card is present.



#13 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 13 February 2013 - 11:21 PM

Ok, then you could try writing a sub routine that uses the try/catch thingy to tell if the card is initially present or not. Then use that info to initialize the variable correctly.

#14 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 13 February 2013 - 11:25 PM

The event handler for card inserted gets called at startup if the card is present

I see, didn't know that. EDIT: Are you sure of the timing here, I mean so that the event handler actually gets called prior to your first write attempt? Not that this is likely to cause a hang nor file coruption though.

#15 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 13 February 2013 - 11:48 PM

I see, didn't know that. EDIT: Are you sure of the timing here, I mean so that the event handler actually gets called prior to your first write attempt? Not that this is likely to cause a hang nor file coruption though.

Maybe. Either way, instead of being an if statement for the first write, it's now a try/catch statement. I'm pretty sure it gets called, because the way my code is now, the card insert event handler is the only thing that makes my LED green, and it starts up as green.

 

EDIT: I guess my major question is how do I ensure a new file gets created on startup, if it doesn't exist? So far, nothing I've tried works. I can write to an existing file quite easily. I just can't create one.



#16 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 14 February 2013 - 07:00 AM

That seems really odd. I suppose you've allready tried different cards (2GB, 4GB, HC, non-HC), different formatting (FAT, FAT32), etc?

 

EDIT: If I can find the time, I'll try the same on an N+ tonight and see what happens. I know you got an N+2 but would still be interesting to know.



#17 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 14 February 2013 - 04:52 PM

Ok, so I tried running the following stripped down version of your code on my N+ (e.g. not an N2+) running firmware version 4.2.0.1:

using System;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware;using SecretLabs.NETMF.Hardware.NetduinoPlus;using System.IO;using SecretLabs.NETMF.IO;using Microsoft.SPOT.IO;using System.Text;using System.Threading;namespace SDReadTest{    public class Program    {        public static OutputPort confirm = new OutputPort(Pins.ONBOARD_LED, false);        public static bool cardInserted = false;        public static void Main()        {            RemovableMedia.Insert += new InsertEventHandler(SD_Insert);            RemovableMedia.Eject += new EjectEventHandler(SD_Eject);            while (true) // ERMAHGERD LERP            {                if (cardInserted)                {                    try                    {                        using (var fileStream = new FileStream(@"SDtest.txt", FileMode.Append, FileAccess.Write))                        {                            StreamWriter fWrite = new StreamWriter(fileStream);                            fWrite.WriteLine("Testing...derp derp derp");                            fWrite.Close();                        }                    }                    catch (Exception ex)                    {                        Debug.Print(ex.Message);                    }                }                Thread.Sleep(1000);            }        }        static void SD_Insert(object sender, MediaEventArgs args)        {            confirm.Write(true);            cardInserted = true;        }        static void SD_Eject(object sender, MediaEventArgs args)        {            confirm.Write(false);            cardInserted = false;        }    }}

 

...and it works perfectly. I inserted a freshly FAT (not FAT32) formatted 2GB SD (not SDHC) card and I could cycle the card at any moment and it continues where it "left off" writing to the file. Also, I took the card out and inserted into my PC and successfully opened the file "test.txt" (created by the N+) in Notepad. I then re-inserted the card in the N+ and again it continued to append new lines to the file. The on-board LED went off and on as I cycled the card.

 

It would be a good idea for you to run the exact same code as above and if (1) it works, I suggest you start removing stuff one piece at a time from your original converging to the stripped down version until it works. By then you should know what causes the problem and can go from there. 

 

If however (2), the stripped code doesn't work then we could perhaps have somebody else try the stripped down code on a N2+ and take it from there.

 

Oh, and I verified that the card inserted even fired before the main part of the application started. Actually the event fired directly after this line of code:

RemovableMedia.Eject += new EjectEventHandler(SD_Eject);

  • mHammer likes this

#18 Verdris

Verdris

    Advanced Member

  • Members
  • PipPipPip
  • 128 posts
  • LocationReno, NV

Posted 14 February 2013 - 06:20 PM

For giggles, I deployed your code to my NP1. Works fine. I left both my NP2s at work, so I'll port the code this afternoon and report back.



#19 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 14 February 2013 - 06:34 PM

Will be interesting to learn of your findings. In the meantime, what does "ERMAHGERD LERP" mean? To me It looks like Vogon poetry or the last words of someone being strangled :-)

#20 emg

emg

    Advanced Member

  • Members
  • PipPipPip
  • 129 posts

Posted 14 February 2013 - 07:33 PM

lol.

Let me Google that for you

 

My personal favourite: Ermahgerd Translator

 

 







Also tagged with one or more of these keywords: sd, uSd, datacard, datalogging

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.