Main Site Documentation

SD card detection thread


#1

So I had started a previous topic in the forum regaurding this but I cannot find it so im going to start a new one. Below is the detection thread I wrote to monitor the SD port and mount the file system when one is connected.

public static void sD_Detection_Thread()  //there is no interrupt handler for sd cards implimented on this chip, so we will use a very low prioriety thread
        {                                         //to scan the sD port once every second that will function as our interrupt handler.
            GPainter paint = new GPainter();  //Create a method to handle individual file transfers, make this tidy

            while (true)
            {
                Thread.Sleep(2000);  //1 second intervals between iterations of this threads main loop
                if (sd == null)
                {
                   
                    try  //Try to mount the SD media's file system
                    {

                        sd = new PersistentStorage("SD");
                        
                        sD_Inserted = true;
                        

                        sd.MountFileSystem();  //Mount the file system of the SD memory card
                        if (VolumeInfo.GetVolumes()[0].IsFormatted)
                        {
                            string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                            string[] files = Directory.GetFiles(rootDirectory);
                            string[] folders = Directory.GetDirectories(rootDirectory);
                            paint.Clear();
                            paint.PrintSmall(0, 0, "SD device connected");
                            FEZ_Extensions.Graphical128x64Display.Flush(paint.vram);
                            Thread.Sleep(2000);
                        }
                    }
                    catch  //SD's file system could not be mounted.
                    {
                   //     paint.Clear();
                   //     paint.PrintSmall(0, 0, "Unable to mount SD [Invalid Format]");
                   //     sD_Inserted = true;
                   //     FEZ_Extensions.Graphical128x64Display.Flush(paint.vram);
                        
                    }
                }
            }
        }

I invoke the thread through the following code in my main code section.

Thread SdThreadHandler;

            SdThreadHandler = new Thread(sD_Detection_Thread);
            SdThreadHandler.Start();  //This thread will run forever with an internal sleep of 1 second between iterations.
            SdThreadHandler.Priority = ThreadPriority.Lowest;  //This is not a high priority thread, just need it to scan occasionally.

My question is that my applications become extremely laggy while this thread is going until it mounts a SD card. So like if I am currently only working with a USB drive the whole interface I have programmed seems to slow down drastically. Is there any tips to avoid this problem or obvious errors I have made in my code?

Regards,
Aaron


#2

I don’t have an SD card to test, but in general I might aproach this like:

  1. Comment out everything between “if (sd ==null) {…}” and run to see if still slow. Just to quickly see we not chasing some other issue. If fast/normal, then we know issue is PersistenStorage and/or Mount overhead.
  2. Can you move “sd = new PersistentStorage(“SD”);” above the loop so as not to create again each loop? Or will it throw?
  3. Also try moving the thread priority above the thread start. Just wondering if the framework is ignoring the property after start.
  4. I wonder if there is a pin to monitor/event for insert even if not supported in the driver?

#3

I could be wrong but I believe mounting the SD has some blocking issues. But this should only occur when the SD card is inserted so it really shouldn’t be a problem unless the user is popping the card in an out over and over.

You can look at Pyxis2 Beta 1 for how I handle SD detection. Look at the desktop (which creates a DispatchTimer and Controller which handles the actual detection).

Good luck!


#4

I was reading through some threads of other people and I found someone using the line:

if (sd == null && GHIElectronics.NETMF.IO.PersistentStorage.DetectSDCard())

before trying to use the ps = new command, it seems that command was creating my lag and placing that check in front of it got rid of the problem.

I am not sure about if the thread priority needs to be above or below the start command, i’ll run a test with both ways to check for this.

regards
Aaron


#5

Here is how I did it a while back. The first time you call “PersistentStorage.DetectSDCard();” the SD card is reset so it takes some before you can do anythign else with the SD card. I got around this by calling it in the constructor and having a 2 second delay before the timer to periodically check the SD card state starts.

using System;
using System.IO;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Hardware.UsbClient;

using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.Hardware;

namespace Soigeneris
{
    public delegate void USBClientEvents(object sender, USBClientEventArgs e);
    public enum ClientState { Dissconnected, Connected, Attached };
    public enum SDState { Removed, Inserted };

    public class Storage
    {
        public event USBClientEvents USBClientState;

        static USBC_MassStorage ms;
        static ExtendedTimer msTimer;
        static ClientState clState = ClientState.Dissconnected;
        static USBClientController.State USBState = USBClientController.State.Default; // used by USBTimer callback
        static USBClientController.State lastState = USBClientController.State.Stopped; // for debugging
        static USBClientEventArgs usbArgs;

        static PersistentStorage sd;
        static SDState sdState = SDState.Removed;
        static bool sdInserted = false; // used by sdTimer callback

        /// <summary>
        /// Constructor, instantiates local variables
        /// </summary>
        public Storage()
        {
            sdInserted = PersistentStorage.DetectSDCard();

            ///////////////////////////////////////////////////////////////////
            // slower polliong rates cause unrecognized device errors
            msTimer = new ExtendedTimer(new TimerCallback(USBTimerHandler), null, 2000, 100);
            ///////////////////////////////////////////////////////////////////

            ms      = USBClientController.StandardDevices.StartMassStorage();
            usbArgs = new USBClientEventArgs(ClientState.Dissconnected);
        }

        /// <summary>
        /// public access to state of SD card
        /// </summary>
        public SDState SD_State
        {
            get
            {
                return sdState;
            }
        }

        /// <summary>
        /// Looks for a change in SD card inserted state on each tick
        /// </summary>
        /// <param name="target"></param>
        void sdTimerHandler(/*object target*/)
        {
            sdInserted = PersistentStorage.DetectSDCard();
            
            // if one of the other has changed raise fire event
            if (sdInserted & sdState != SDState.Inserted)
            {
                // fire SD_Inserted
                //Debug.Print("SD card has been inserted");
                sd = new PersistentStorage("SD");
                //ms.AttachLun(0, sd, " ", " ");
                sd.MountFileSystem();
                sdState = SDState.Inserted;
            }
            else if (!sdInserted & sdState != SDState.Removed)
            {   
                // fires SD_Removed
                //Debug.Print("SD card has been removed");
                try
                {
                    sd.UnmountFileSystem();
                }
                catch
                {
                    //Debug.Print("SD file system was not mounted");
                }
                sd.Dispose();
                sdState = SDState.Removed;
            }
        }

        /// <summary>
        /// Check USB cable connection state periodically
        /// </summary>
        /// <param name="target"></param>
        void USBTimerHandler(object target)
        {
            sdTimerHandler();
            USBState = USBClientController.GetState();

            // for debugging
            if (lastState != USBState) { 
                Debug.Print("USBState " + USBState.ToString());
                lastState = USBState;
            }
            
            if (USBState == USBClientController.State.Running & clState == ClientState.Dissconnected)
            {
                //Debug.Print("USB cable has been connected");
                clState = ClientState.Connected;
                usbArgs.USBState = ClientState.Connected;
                OnUSBEvent(usbArgs);
            }
            else if (USBState != USBClientController.State.Running & clState != ClientState.Dissconnected)
            {
                //Debug.Print("USB cable has been dissconnected");
                clState = ClientState.Dissconnected;
                usbArgs.USBState = ClientState.Dissconnected;
                OnUSBEvent(usbArgs);
            }
        }

        /// <summary>
        /// Invokes the USBEvent; called whenever USB Client state changes
        /// </summary>
        /// <param name="e">USB Client state</param>
        protected virtual void OnUSBEvent(USBClientEventArgs e)
        {
            if (USBClientState != null)
            {
                USBClientState(this, e);
            }
        }

        /// <summary>
        /// Attach to PC as mass storage device if SD card is inserted
        /// </summary>
        public void attach()
        {
            if (sdState == SDState.Inserted)
            {
                sd.UnmountFileSystem();
                ms.AttachLun(0, sd, " ", " ");
                ms.EnableLun(0); // enable host access
                clState = ClientState.Attached;
                usbArgs.USBState = ClientState.Attached;
                OnUSBEvent(usbArgs);
                //Debug.Print("Attached as MassStorage device now.");
            }
            else
            {
                //Debug.Print("SD Card is not inserted, cannot create MSD");
            }
        }

        /// <summary>
        /// Detach SD as mass storage device
        /// </summary>
        public void detach()
        {
            Debug.Print("detach clState:" + clState.ToString() + " sdState:" + sdState.ToString());
            if (sdState == SDState.Inserted & clState == ClientState.Dissconnected)
            {
                ms.DisableLun(0);

                ///////////////////////////////////////////////////////////////
                // restart mass storage to prevent reconnect errors
                clState = ClientState.Dissconnected;
                USBClientController.Stop();
                Thread.Sleep(500);
                USBClientController.StandardDevices.StartMassStorage();
                ///////////////////////////////////////////////////////////////

                sd.MountFileSystem();
                sdState = SDState.Inserted;
                Debug.Print("SD now available to FEZ");
            }
        }

    }

    #region KeyEventArgs helper class

    /// <summary>
    /// This classed used to pass KeyPressed Events
    /// </summary>
    public class USBClientEventArgs : EventArgs
    {
        public USBClientEventArgs(ClientState usbState)
        {
            this.USBState = usbState;
        }

        public ClientState USBState;

    }

    #endregion
}