Can't figure out weird behavior with SD cards

At first I was stumped by the RemovableMedia Insert and Eject events, until I read here that they don’t get fired until the filesystem is mounted and unmounted. So I decided to go ahead with the example provided, and to use a thread to poll via the PersistentStorage.DetectSDCard() method.

I’m having all kinds of problems with that approach. While it seems to work once, provided that the SD is inserted before I start the program, it does not work when I am running and try to remove/reinsert multiple times.

I’ve attached my code below – can anyone see something that I’m doing that’s obviously wrong?


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.IO;
using Microsoft.SPOT.IO;
using System.IO;

namespace FezSdXmlTest
{
    public class Program
    {
        public static void Main()
        {
            SdTest test = new SdTest();
            test.Run();

            // these events don't work as one might expect
            RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
            RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);

            while( true) {
                Thread.Sleep( 100);
            }
        }

        /// <summary>
        /// Doesn't work!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void RemovableMedia_Eject(object sender, MediaEventArgs e)
        {
        }

        /// <summary>
        /// Doesn't work!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void RemovableMedia_Insert(object sender, MediaEventArgs e)
        {
        }

        public class SdTest
        {
            PersistentStorage sd = null;

            public void Run()
            {
                    RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
                    RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);

                    new Thread( SdMountThread).Start();
            }

            void SdMountThread()
            {
                while( true) {
                    try {
                        bool sd_exists = PersistentStorage.DetectSDCard();
                        if( sd_exists) {
                            Thread.Sleep( 50);
                            sd_exists = PersistentStorage.DetectSDCard();
                        }

                        if( sd_exists && sd == null) {
                            Debug.Print( "SD card inserted -- mounting SD filesystem");
                            sd = new PersistentStorage( "SD");
                            Debug.Print( "Mounting filesystem");
                            sd.MountFileSystem();
                        } else if( !sd_exists && sd != null) {
                            Debug.Print( "SD card removed -- unmounting filesystem");
                            try {
                                sd.UnmountFileSystem();
                            } catch( Exception) {
                                Debug.Print( "SD filesystem not unmounted cleanly");
                            }
                            sd.Dispose();
                            sd = null;
                        }
                    } catch( Exception ex) {
                        Debug.Print( ex.Message);
                        if( sd != null) {
                            sd.Dispose();
                            sd = null;
                        }
                    }

                    Thread.Sleep( 100);
                }
            }

            /// <summary>
            /// Doesn't work as expected -- gets fired after we unmount the filesystem
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void RemovableMedia_Eject(object sender, MediaEventArgs e)
            {
                Debug.Print( "RemovableMedia Eject event fired");
                /*
                try {
                    sd.UnmountFileSystem();
                } catch( Exception ex) {
                    Debug.Print( "Could not unmount filesystem: " + ex.Message);
                }
                 */
            }

            /// <summary>
            /// Doesn't work as expected
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void RemovableMedia_Insert(object sender, MediaEventArgs e)
            {
                Debug.Print( "RemovableMedia Insert event fired");
                try {
                    if( VolumeInfo.GetVolumes()[0].IsFormatted) {
                        Debug.Print("Available folders:");
                        string[] strs = Directory.GetDirectories(e.Volume.RootDirectory);
                        for (int i = 0; i < strs.Length; i++)
                            Debug.Print(strs[i]);
 
                        Debug.Print("Available files:");
                        strs = Directory.GetFiles(e.Volume.RootDirectory);
                        for (int i = 0; i < strs.Length; i++)
                            Debug.Print(strs[i]);
                    } else {
                        Debug.Print( "SD card is not formatted");
                    }
                } catch( Exception ex) {
                    Debug.Print( "Could not mount filesystem: " + ex.Message);
                }
            }
        }
    }
}


What I have noticed during debugging is two things: either my breakpoints stop working (I can tell because the Debug.Print statement string ends up in the output window, but the debugger never stops on that line), or sd magically gets instantiated, even though I explicitly clean up when the SD card is removed. Because of the magic instantiation, it skips the code that should be responsible for instantiating sd and mounting the filesystem.

Something must be happening behind the scenes, because after I remove the SD card and put a breakpoint on the sd == null check, sd is null! But as soon as I insert the card and put a breakpoint on that check again, sd is no longer null. And I had a breakpoint on the sd instantation, and it was never hit. Can anyone think of something that could cause instantiation to happen automatically like this?

I don’t clearly understand the problem. It should work fine.
First, use our provided example as-is to make sure there are no bugs.
After deploying using Visual Studio, connect to the board through MFDeploy where you can see the debug messages easier. Remove & insert SD. What do you see?
Maybe the board is resetting when you insert the SD card so try a power adapter.

As another data point, my Panda II resets when I insert an SD card. This happens when running on USB, and I have not tried it when running on an external power adapter.

Mike, I think you’ve nailed the problem, but unfortunately I don’t have my power adapter with me at the moment. The sample code exhibits the same problem, but today I’m working on my laptop and my audio is conveniently on. When I start the GHI sample code with the SD card inserted, the card is detected. When I remove the card, removal is detected. When I reinsert the card, I get the Windows sound notification for USB device removal and reconnection, so I think what you’ve said about the board resetting is correct. I’ll give it a try tomorrow when I have access to the power adapter and will post my results. Thanks very much!

godefroi, thanks for the info. I should have mentioned that I also am using a Panda II.

Dave, I think you may have run into a known problem.
Some SD cards seem to drive too much current for the Panda II when inserted, and that resets the boards.

A work arround is to add some capacitors to the board. Please see this old thread:
http://www.tinyclr.com/forum/2/3277/

Have fun :slight_smile: !

I wonder if the MCU on the Panda II is under-decoupled. There’s only two total decoupling caps, and they’re not particularly close to the MCU. Further, a somewhat larger bulk cap between VCC and GND might be advisable.

I agree, I think it is the problem. I am using both domino and panda II boards, and the problems occurs only with the panda II, using the same software and same SD cards. ::slight_smile:

Thanks for the info, everyone. Interestingly enough, I happened to use a SanDisk 2GB card in my Panda II, but used an Apacer 2GB in my Netduino Plus. I’ll give the Apacer card a try in the Panda II tomorrow, as I would rather not have to add the caps to the board right now.

I found another Apacer card and that doesn’t work, either. I wonder what brand GHI used for testing? I’d like to order a couple of those.

Hmmm… on second thought, maybe I should just add the caps…

I just tried while powering via the DC jack with 5v, it resets when inserting, not when removing. Same as when powering via USB.

I tried with both a SanDisk 2GB and a PNY 2GB. Same results.

Shouldnt the external voltage be at least 6V?

Yes, sorry, I meant 9v. The regulators on the Panda II are LDO, so you can power with as little as (I think) 5.4v, in theory, but normally you’d want a little headroom there.