Error while trying to write on SD card

I’m trying to take a picture using the camera module and writing it on an SD card. Sometimes, I’m getting an IO exception but don’t know why. I reduced my code to the following:


void ProgramStarted()
{
            camera.PictureCaptured += camera_PictureCaptured;
            camera.TakePicture();
            Debug.Print("Program Started");
}

void camera_PictureCaptured(Camera sender, GT.Picture e)
{
           Debug.Print(sdCard.IsCardMounted ? "mounted!" : "not mounted!");
           sdCard.StorageDevice.WriteFile("test.bmp", e.PictureData);
}

My debug message tells me that the SD card is mounted. In maybe 1 of 10 attempts writing the file fails with the following exception:

I tried different, empty SD cards, using FAT or FAT32 file system. Even stepping through the program using the debugger didn’t change anything. I found different threads regarding similar problems ending up with the suggestion not to use the SD card, but I’m not going to accept this until I understand what’s causing the issue. :wink:

1 Like

try a couple of simple changes.

Set a Boolean flag so if you’re writing, you don’t try to do that again.

Keep a global image counter, and when writing a file use a new filename each time (append the counter to the filename).

See if either of those scenarios works more reliably, less reliably, or the same reliability…

Try to use plain NETMF to write the file.
You can use “System.IO.File” class to do so.
The class works nearly the same as in full .NET:
Create, write, Close.
The file path would be @ “\SD\test.bmp”.

And don’t Forget to wait a while after writing the file to SD before you reset or use the FlushAll method on the Storrage (look in Forums for it)

Hi MrAlex92

this code seems to work:


using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

//The following references must be added
using Microsoft.SPOT.IO;
using System.IO;



namespace Camera_SdCard_Test
{
    public partial class Program
    {
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            camera.PictureCaptured += camera_PictureCaptured;
            camera.CameraConnected += camera_CameraConnected;

            // SD-Card stuff 
            //*******************************************************************************************
            try
            {
                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                    string[] files = Directory.GetFiles(rootDirectory);
                    string[] folders = Directory.GetDirectories(rootDirectory);

                    Debug.Print("Files available on " + rootDirectory + ":");
                    for (int i = 0; i < files.Length; i++)
                    {
                        Debug.Print(files[i]);
                    }
                    Debug.Print("Folders available on " + rootDirectory + ":");
                    for (int i = 0; i < folders.Length; i++)
                    {
                        Debug.Print(folders[i]);
                    }
                }
                else
                {
                    Debug.Print("Storage is not formatted. " +
                        "Format on PC with FAT32/FAT16 first!");
                }
            }
            catch
            {
                Debug.Print("SD-Card could not be opened!");
            }

            //******************************************************************

   
            Debug.Print("Program Started");
        }


        void camera_CameraConnected(Camera sender, EventArgs e)
        {
            camera.CurrentPictureResolution = Camera.PictureResolution.Resolution320x240;

            camera.TakePicture();
            Debug.Print("Message: Camera connected");
        }

        void camera_PictureCaptured(Camera sender, GT.Picture e)
        {
            Debug.Print(sdCard.IsCardMounted ? "mounted!" : "not mounted!");
            string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
            Debug.Print("Root directory: " + rootDirectory);
            sdCard.StorageDevice.WriteFile(rootDirectory + @ "\" + "test.bmp", e.PictureData);
            FinalizeVolumes();
            Debug.Print("Ready");
        }

        private void FinalizeVolumes()
        {
            VolumeInfo[] vi = VolumeInfo.GetVolumes();
            for (int i = 0; i < vi.Length; i++)
                vi[i].FlushAll();
        }
    }
}


@ Brett - As the program only writes the file once, this should never happen. But I tried changing the file name each time I start the simple program - didn’t change anything. Doesn’t seem to be related to overwriting existing files.

@ RoSchmi - Thanks for your code, but it doesn’t work more reliably. When the exception occurs, the first debugging steps are fine (I’ll see the “files available” output and so on), but the call of WriteFile() crashes and FinalizeVolumes() doesn’t get called.

@ Reinhard Ostermeier - I gave pure NETMF a try, but ended up with the same exception again.

The next thing I tried was taking a look at the SD cards after the crash. Sometimes, the file had been created and the first lines of the picture were written, sometimes not even the file had been created. Am I missing some important point on how to use SD cards properly with NETMF 4.3? After downgrading my Spider to NETMF 4.2, everythink is working fine now…

@ MrAlex92 -
I can confirm your observation.
With NETMF 4.3 GHI SDK 2015 R1 my code runs fine on the raptor mainboard.
On the spider the cameraConnected event is never fired and on a camera.TakePicture() command an exception is thrown.
#### Exception System.InvalidOperationException - 0x00000000 (1) ####
#### Message: No camera is connected.
#### Gadgeteer.Modules.GHIElectronics.Camera::TakePicture [IP: 0015] ####
#### Gadgeteer.Modules.GHIElectronics.Button::OnButtonEvent [IP: 0057] ####
#### System.Reflection.MethodBase::Invoke [IP: 0000] ####
#### Gadgeteer.Program::DoOperation [IP: 001a] ####
#### Microsoft.SPOT.Dispatcher::PushFrameImpl [IP: 0054] ####
#### Microsoft.SPOT.Dispatcher::PushFrame [IP: 001a] ####
#### Microsoft.SPOT.Dispatcher::Run [IP: 0006] ####
#### Gadgeteer.Program::Run [IP: 001d] ####

I think GHI should have a look on this issue.

I can confirm it running fine on my Raptor with NETMF 4.3. On the Spider, the picture is taken correctly and I’m able to show it on the T35 display, but writing to the SD card still doesn’t work when using NETMF 4.3.
Today, I tried another camera to ensure that it’s not related to a faulty module, but I’m getting the same results as with my first one.
I’m going to continue my project on the Raptor, but I’d really like to fix this. As in most cases the exception occurs after more than half of the file has already been written, I’m thinking about manual buffering and writing to the card more slowly, maybe this will help. :think:

@ MrAlex92 -
Curious, when I run the programm on the spider it seems, that it is the camera module that does not work properly.
This was discussed in this thread:
https://www.ghielectronics.com/community/forum/topic?id=19360
But it should be fixed in the SDK 2015 R1 Pre-Release 1 (which I am using)… ??

@ RoSchmi - I don’t think my problem is related to that error, as the conversion seems to work properly. But thanks for the time you’re spending on my problem!

I found a solution using manual buffering as I thought about in my last post. I’m now writing to the card like this:

int bufferSize = 8;
using (FileStream fs = new FileStream(@ "\SD\test.bmp", FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize))
{
    fs.Write(e.PictureData, 0, e.PictureData.Length);
    fs.Close();
}

I wasn’t able to find the default buffer size, but somwhere on the old netmf codeplex forums, 512 was suggested. Using 512 as buffer size, I’m encountering the same exception as with the default writing method on the spider, but it works fine on the raptor, so maybe it’s the default setting…

I just had a look on my CodeShare project
FEZ/PC Bluetooth File Transfer Server/Client
https://www.ghielectronics.com/community/codeshare/entry/823
which is used to transfer files from PC to Spider via bluetooth and write to SD-Card (Class BtFtpServer.cs). I do not change the default buffer size and the program still works.
Did you consider that a short Gadgeteer cable should be used to connect the SD-Card module?
There were reports that some kinds of SD Cards do not work. I’m actually using a Kingston SD4/4GB Card. I’m actually using the normal size SD-Card module, not the discontinued Micro-SD-Card Module