Suggestion: re-write SDFileSystem

27 Feb 2015

Here's a crude example of how to modify my library for DMA support:

SDFileSystem.cpp

//NOTE: Add this between the includes and the constructor
#include "rtos.h"

namespace
{
enum ThreadSignals {
    SIG_DMA_DONE = (1 << 2)
};

unsigned int m_DmaChannelTable[18 * 4] __attribute__((aligned(512))) = {};
osThreadId threadId;

void onDmaIrq()
{
    //Clear the interrupt flags
    LPC_DMA->INTA0 = (1 << 6) | (1 << 7);

    //Signal the thread that the DMA transfer has finished
    osSignalSet(threadId, SIG_DMA_DONE);
}

void dmaInit()
{
    //Enable the AHB clock to the DMA controller and reset it
    LPC_SYSCON->SYSAHBCLKCTRL0 |= (1 << 20);
    LPC_SYSCON->PRESETCTRL0 |= (1 << 20);
    LPC_SYSCON->PRESETCTRL0 &= ~(1 << 20);

    //Configure the DMA controller and enable it
    LPC_DMA->SRAMBASE = (unsigned int)m_DmaChannelTable & 0xFFFFFE00;
    LPC_DMA->CTRL = 0x00000001;

    //Configure channel 6 (SPI0_RX_DMA)
    LPC_DMA->CFG6 = 0x00010001;
    LPC_DMA->INTENSET0 = (1 << 6);
    LPC_DMA->ENABLESET0 |= (1 << 6);

    //Configure channel 7 (SPI0_TX_DMA)
    LPC_DMA->CFG7 = 0x00020001;
    LPC_DMA->INTENSET0 = (1 << 7);
    LPC_DMA->ENABLESET0 |= (1 << 7);

    //Set the DMA IRQ vector and enable it
    NVIC_SetVector(DMA_IRQn, (uint32_t)onDmaIrq);
    NVIC_EnableIRQ(DMA_IRQn);
}

void dmaRead(char* buffer, int length)
{
    //Adjust the length
    length -= 1;

    //Configure the SPI controller for 8-bit frames
    LPC_SPI0->TXCTL = 0x07000000;

    //Configure channel 6 and trigger it
    m_DmaChannelTable[25] = 0x40048014;
    m_DmaChannelTable[26] = (unsigned int)buffer + length;
    LPC_DMA->XFERCFG6 = (length << 16) | 0x0000401D;

    //Configure channel 7 and trigger it
    char txByte = 0xFF;
    m_DmaChannelTable[29] = (unsigned int)&txByte;
    m_DmaChannelTable[30] = 0x4004801C;
    LPC_DMA->XFERCFG7 = (length << 16) | 0x0000000D;

    //Wait for the transfer to complete
    threadId = Thread::gettid();
    osSignalWait(SIG_DMA_DONE, osWaitForever);
}

void dmaWrite(const char* buffer, int length)
{
    //Adjust the length
    length -= 1;

    //Configure the SPI controller for 8-bit frames, TX only
    LPC_SPI0->TXCTL = 0x07400000;

    //Configure channel 7 and trigger it
    m_DmaChannelTable[29] = (unsigned int)buffer + length;
    m_DmaChannelTable[30] = 0x4004801C;
    LPC_DMA->XFERCFG7 = (length << 16) | 0x0000101D;

    //Wait for the transfer to complete
    threadId = Thread::gettid();
    osSignalWait(SIG_DMA_DONE, osWaitForever);

    //Set the SPI controller back to normal
    LPC_SPI0->TXCTL = 0x07000000;
}
}

//NOTE: Modify the constructor as indicated
SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz) : FATFileSystem(name), m_Spi(mosi, miso, sclk), m_Cs(cs, 1), m_Cd(cd), m_FREQ(hz)
{
    //NOTE: Add this to the bottom of the constructor code
    dmaInit();
}

//NOTE: Replace readData() with this version
bool SDFileSystem::readData(char* buffer, int length)
{
    char token;
    unsigned short crc;

    //Wait for up to 500ms for a token to arrive
    m_Timer.start();
    do {
        token = m_Spi.write(0xFF);
    } while (token == 0xFF && m_Timer.read_ms() < 500);
    m_Timer.stop();
    m_Timer.reset();

    //Check if a valid start block token was received
    if (token != 0xFE)
        return false;

    //Read the data block using DMA
    dmaRead(buffer, length);

    //Read the CRC16 checksum for the data block
    crc = (m_Spi.write(0xFF) << 8);
    crc |= m_Spi.write(0xFF);

    //Return the validity of the CRC16 checksum (if enabled)
    return (!m_Crc || crc == CRC16(buffer, length));
}

//NOTE: Replace writeData() with this version
char SDFileSystem::writeData(const char* buffer, char token)
{
    //Calculate the CRC16 checksum for the data block (if enabled)
    unsigned short crc = (m_Crc) ? CRC16(buffer, 512) : 0xFFFF;

    //Wait for up to 500ms for the card to become ready
    if (!waitReady(500))
        return false;

    //Send the start block token
    m_Spi.write(token);

    //Write the data block using DMA
    dmaWrite(buffer, 512);

    //Write the CRC16 checksum for the data block
    m_Spi.write(crc >> 8);
    m_Spi.write(crc);

    //Return the data response token
    return (m_Spi.write(0xFF) & 0x1F);
}


And there you have it! This code is written for the LPC1549, but it should be fairly easy to modify for other targets. It uses the official rtos library to sleep the calling thread while data transfer takes place (so accessing the SD card from ISR context is not allowed).

At this point, I don't have any plans to bake DMA support into the library since I don't feel like building my own lightweight HAL layer and keeping up with new targets as they're added. The best way to do this would be if the mbed library provided a non-blocking API for reading/writing from the SPI bus, and hid the actually implementation from the user. Something like the following would work (with a bit of additional template magic of course):

//Read a block of data from an SPI device, and fire a callback when done
void SPI::readNB(char* data, int length, void (*fptr)(SpiResult));

//Write a block of data to an SPI device, and fire a callback when done
void SPI::writeNB(const char* data, int length, void (*fptr)(SpiResult));


Targets with a DMA controller would use it to perform the transfer, while targets without a DMA controller could use interrupts. The important point here is that the transfer takes place in the background, using a microcontroller-independent non-blocking API. This could be extended to other busses as well, such as I2C or Serial. If there's enough support for this kind of API, I may be persuaded to create a separate thread to work on getting it added.

27 Feb 2015

Thank you, Nei. I'll modify sample code and test the performance .

27 Feb 2015

This was made using the regular SDFileSystem library, but using some libraries which try to do the DMA more generalized, might help you as starting point: http://developer.mbed.org/users/Sissors/code/SDFileSystem-RTOS/

01 Mar 2015

This is awesome code!

I get 290kb/s write, 1150kb/s read with Tanscend and 130kb/s write, 1100kb/s read. with Elsonic! It became fast almost 2030% write and 7080% read! Code size is just up 2K byte for RTOS libs.

To Eirk. Thank you for your pointer. I have only LPCXpresso1549 now, but If I want to port other enviromnet , I'll refer you codes .

Regards

28 May 2015

Hi everyone,

I've noticed this issue that Frank ran into regarding inconsistencies of which PinModes are defined across platforms. In the past, the only way to get around this issue has been to add "#if defined" messages for every platform that has different support, as seen in Frank's previous post:

Frank Vannieuwkerke wrote:

Hi Neil,
SWITCH_POS_NO or SWITCH_POS_NC will not work when used with a KL05Z or KL25Z as these do not support interrupt mode.pulldown. Perhaps adding a more verbose message would be helpful (certainly for newbies)?

    //Configure the card detect pin
    if (cdtype == SWITCH_POS_NO) {
    #if defined (TARGET_KL25Z) || (TARGET_KL05Z)
        #error  SWITCH_POS_NO (Uses Interruptin PullDown) is not supported on KL05Z and KL25Z
    #endif
        m_Cd.mode(PullDown);
        m_CdAssert = 1;
        m_Cd.fall(this, &SDFileSystem::onCardRemoval);
    } else if (cdtype == SWITCH_POS_NC) {
        #if defined (TARGET_KL25Z) || (TARGET_KL05Z)
            #error  SWITCH_POS_NC (Uses Interruptin PullDown) is not supported on KL05Z and KL25Z
        #endif
        .....

I've created a pull request that attempts to provide a better mechanism to determine which PinModes are available at runtime. This should make writing libraries that work across platforms easier and cleaner.

You can see the pull request here: https://github.com/mbedmicro/mbed/pull/1141

Would you mind checking out the changes and seeing if they make sense? Does this approach solve some of your problems? Please feel free to leave comments on the pull request!

Thanks!

Brian

01 Sep 2015

Hi Neil,

Many thanks for creating this library. I tried to modify my existing code (using the official SDFileSystem) to use your library but it failed to work. Then I tried your Hello world program and the code given in the header file and it worked just fine. I've discovered that it fails to work when I try to create a folder using the mkdir function. Can you advise how I can create new paths and folders using your library?

Thanks.

Farzan

01 Sep 2015

Farzan Hasani wrote:

Hi Neil,

Many thanks for creating this library. I tried to modify my existing code (using the official SDFileSystem) to use your library but it failed to work. Then I tried your Hello world program and the code given in the header file and it worked just fine. I've discovered that it fails to work when I try to create a folder using the mkdir function. Can you advise how I can create new paths and folders using your library?

Thanks.

Farzan

Hi Farzan, I just tried the old SDFileSystem_HelloWorld, and it was able to create a folder just fine on an LPCXpresso11U68. Which platform are you using? The stdio layer is really hard on memory, and it's possible that my library has slightly higher stack requirements than the old one.

02 Sep 2015

Hi Neil,

Thanks for your prompt reply. I'm using the C027 U-blox platform with LPC1768, so memory shouldn't really be a problem. The old SDFileSystem_HelloWorld works fine on my system (with the old library). Your library also works fine as long as I am reading or writing to the path "/sd/" without any sub-folder.

For example, I used the commented program in your SDFileSystem.h file and it worked fine. Then I modified it to the following:

int main()
{
    sd.mount();
    mkdir("/sd/test",0777);

    //Perform a write test
    printf("\nWriting to SD card...");
    FILE *fp = fopen("/sd/test/sdtest.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "We're writing to an SD card!");
        fclose(fp);
        printf("success!\n");
    } else {
        printf("failed!\n");
    }

    //Perform a read test
    printf("Reading from SD card...");
    fp = fopen("/sd/test/sdtest.txt", "r");
    if (fp != NULL) {
        char c = fgetc(fp);
        if (c == 'W')
            printf("success!\n");
        else
            printf("incorrect char (%c)!\n", c);
        fclose(fp);
    } else {
        printf("failed!\n");
    }

    //Unmount the filesystem
    sd.unmount();
}

This program failed, going to the printf("failed!\n") condition (probably due to the failure of the mkdir function, as it did not create the folder "test" which made the path for reading and writing invalid). Maybe I'm making some basic mistake. Would appreciate your guidance on this. Thanks

03 Sep 2015

Farzan Hasani wrote:

Hi Neil,

Thanks for your prompt reply. I'm using the C027 U-blox platform with LPC1768, so memory shouldn't really be a problem. The old SDFileSystem_HelloWorld works fine on my system (with the old library). Your library also works fine as long as I am reading or writing to the path "/sd/" without any sub-folder.

For example, I used the commented program in your SDFileSystem.h file and it worked fine. Then I modified it to the following:

int main()
{
    sd.mount();
    mkdir("/sd/test",0777);

    //Perform a write test
    printf("\nWriting to SD card...");
    FILE *fp = fopen("/sd/test/sdtest.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "We're writing to an SD card!");
        fclose(fp);
        printf("success!\n");
    } else {
        printf("failed!\n");
    }

    //Perform a read test
    printf("Reading from SD card...");
    fp = fopen("/sd/test/sdtest.txt", "r");
    if (fp != NULL) {
        char c = fgetc(fp);
        if (c == 'W')
            printf("success!\n");
        else
            printf("incorrect char (%c)!\n", c);
        fclose(fp);
    } else {
        printf("failed!\n");
    }

    //Unmount the filesystem
    sd.unmount();
}

This program failed, going to the printf("failed!\n") condition (probably due to the failure of the mkdir function, as it did not create the folder "test" which made the path for reading and writing invalid). Maybe I'm making some basic mistake. Would appreciate your guidance on this. Thanks

Hi Farzan, will it create a file in a folder that has already been created? The LPC1768 uses a different standard library than most of the other platforms, and one of the notable differences is the stdio layer. It's possible that's why I can't reproduce your issue. Try calling sd.mkdir() instead and see if that works. You could trying adding some debugging code to FATFileSystem::mkdir() in FATFileSystem.cpp to indicate if its failing or not, and what the return code is. Also, try switching to mbed-src, and adding some debugging code to mkdir() in retarget.cpp.

03 Sep 2015

Hi Neil, I've already tried sd.mkdir(). Same result. I'll try your other suggestions and let you know what I find

04 Sep 2015

Farzan Hasani wrote:

Hi Neil, I've already tried sd.mkdir(). Same result. I'll try your other suggestions and let you know what I find

Hmm... That would seem to implicate FatFs as the culprit... Let me know what the f_mkdir() return value is in FATFileSystem::mkdir().

05 Oct 2015

Hi Neil, apologies for the late feedback. The library was able to write to already created folders which served the purpose for further development of my project, so this issue was put on the back-burner. Now I've got the major problems sorted out, so it's time to address this.

I've shifted to the mbed 1768 platform now (the C027 platform was damaged by some unrelated issue). The f_mkdir() return value is 5, which corresponds to FR_NO_PATH. I've tried to trace it further and I've narrowed it down to the follow_path function in ff.cpp. An extract is shown here with the printf statement indicating the failure point.

static
FRESULT follow_path (	/* FR_OK(0): successful, !=0: error code */
	FATFS_DIR* dp,			/* Directory object to return last directory and found object */
	const TCHAR* path	/* Full-path string to find a file or directory */
)
{
	FRESULT res;
	BYTE *FATFS_DIR, ns;


#if _FS_RPATH
	if (*path == '/' || *path == '\\') {	/* There is a heading separator */
		path++;	dp->sclust = 0;				/* Strip it and start from the root directory */
	} else {								/* No heading separator */
		dp->sclust = dp->fs->cdir;			/* Start from the current directory */
	}
#else
	if (*path == '/' || *path == '\\')		/* Strip heading separator if exist */
		path++;
	dp->sclust = 0;							/* Always start from the root directory */
#endif

	if ((UINT)*path < ' ') {				/* Null path name is the origin directory itself */
		res = dir_sdi(dp, 0);
		dp->FATFS_DIR = 0;
	} else {								/* Follow path */
		for (;;) {
			res = create_name(dp, &path);	/* Get a segment name of the path */
			if (res != FR_OK) break;
			res = dir_find(dp);				/* Find an object with the sagment name */
			ns = dp->fn[NSFLAG];
			if (res != FR_OK) {				/* Failed to find the object */
				if (res == FR_NO_FILE) {	/* Object is not found */
					if (_FS_RPATH && (ns & NS_DOT)) {	/* If dot entry is not exist, */
						dp->sclust = 0; dp->FATFS_DIR = 0;	/* it is the root directory and stay there */
						if (!(ns & NS_LAST)) continue;	/* Continue to follow if not last segment */
						res = FR_OK;					/* Ended at the root directroy. Function completed. */
					} else {							/* Could not find the object */
						if (!(ns & NS_LAST)) { printf("FAILS HERE\n"); res = FR_NO_PATH; }	/* Adjust error code if not last segment */
					}
				}
				break;
			}
			if (ns & NS_LAST) break;			/* Last segment matched. Function completed. */
			FATFS_DIR = dp->FATFS_DIR;						/* Follow the sub-directory */
			if (!(FATFS_DIR[DIR_Attr] & AM_DIR)) {	/* It is not a sub-directory and cannot follow */
				res = FR_NO_PATH; break;
			}
			dp->sclust = ld_clust(dp->fs, FATFS_DIR);
		}
	}

	return res;
}

I've checked the ff.cpp file with the old SDFileSystem (in which mkdir works) and this part is a bit different. Please see if you can resolve this. Let me know if you need me to debug further. Thanks

10 Oct 2015

Thanks Farzan. I'm in the middle of a project right now, but I'll look into this at some point.

16 Oct 2015

Neil First of all I think your code is excellent, not only in its functionality but the actual syntax and style (very easy to read and understand) I was wondering if it is possible to use your SDCard library with a SD card that does not use the card inserted pin? If so how would I call the class? I imported your code into my application and it compiled OK, along with the FATFile library, I then tried to run a test using this code. The end result using two different types of SD cards was that nothing was written to the SDCard.

SDFileSystem sd(PB_15,PB_14,PB_13,PB_12,"sd");

/ Main function */ int main() {

test code to write to sd card mkdir("/sd/mydir",0777); FILE *fp = fopen("/sd/mydir/sdtest.txt","w"); if(fp == NULL){ error("could not open file for write\n"); } fprintf(fp,"hello SD card"); fclose(fp);

Any suggestions or help would be much appreciated.

Cheers Rudy

16 Oct 2015

Rudy Van De Poll wrote:

Neil First of all I think your code is excellent, not only in its functionality but the actual syntax and style (very easy to read and understand) I was wondering if it is possible to use your SDCard library with a SD card that does not use the card inserted pin? If so how would I call the class? I imported your code into my application and it compiled OK, along with the FATFile library, I then tried to run a test using this code. The end result using two different types of SD cards was that nothing was written to the SDCard.

SDFileSystem sd(PB_15,PB_14,PB_13,PB_12,"sd");

/ Main function */ int main() {

test code to write to sd card mkdir("/sd/mydir",0777); FILE *fp = fopen("/sd/mydir/sdtest.txt","w"); if(fp == NULL){ error("could not open file for write\n"); } fprintf(fp,"hello SD card"); fclose(fp);

Any suggestions or help would be much appreciated.

Cheers Rudy

Hi Rudy. You should be able to use my library without a card detect pin, but you need to manually call sd.mount() and sd.unmount().

16 Oct 2015

Farzan Hasani wrote:

Hi Neil, apologies for the late feedback. The library was able to write to already created folders which served the purpose for further development of my project, so this issue was put on the back-burner. Now I've got the major problems sorted out, so it's time to address this.

I've shifted to the mbed 1768 platform now (the C027 platform was damaged by some unrelated issue). The f_mkdir() return value is 5, which corresponds to FR_NO_PATH. I've tried to trace it further and I've narrowed it down to the follow_path function in ff.cpp. An extract is shown here with the printf statement indicating the failure point.

static
FRESULT follow_path (   /* FR_OK(0): successful, !=0: error code */
    FATFS_DIR* dp,          /* Directory object to return last directory and found object */
    const TCHAR* path   /* Full-path string to find a file or directory */
)
{
    FRESULT res;
    BYTE *FATFS_DIR, ns;
 
 
#if _FS_RPATH
    if (*path == '/' || *path == '\\') {    /* There is a heading separator */
        path++; dp->sclust = 0;             /* Strip it and start from the root directory */
    } else {                                /* No heading separator */
        dp->sclust = dp->fs->cdir;          /* Start from the current directory */
    }
#else
    if (*path == '/' || *path == '\\')      /* Strip heading separator if exist */
        path++;
    dp->sclust = 0;                         /* Always start from the root directory */
#endif
 
    if ((UINT)*path < ' ') {                /* Null path name is the origin directory itself */
        res = dir_sdi(dp, 0);
        dp->FATFS_DIR = 0;
    } else {                                /* Follow path */
        for (;;) {
            res = create_name(dp, &path);   /* Get a segment name of the path */
            if (res != FR_OK) break;
            res = dir_find(dp);             /* Find an object with the sagment name */
            ns = dp->fn[NSFLAG];
            if (res != FR_OK) {             /* Failed to find the object */
                if (res == FR_NO_FILE) {    /* Object is not found */
                    if (_FS_RPATH && (ns & NS_DOT)) {   /* If dot entry is not exist, */
                        dp->sclust = 0; dp->FATFS_DIR = 0;  /* it is the root directory and stay there */
                        if (!(ns & NS_LAST)) continue;  /* Continue to follow if not last segment */
                        res = FR_OK;                    /* Ended at the root directroy. Function completed. */
                    } else {                            /* Could not find the object */
                        if (!(ns & NS_LAST)) { printf("FAILS HERE\n"); res = FR_NO_PATH; }  /* Adjust error code if not last segment */
                    }
                }
                break;
            }
            if (ns & NS_LAST) break;            /* Last segment matched. Function completed. */
            FATFS_DIR = dp->FATFS_DIR;                      /* Follow the sub-directory */
            if (!(FATFS_DIR[DIR_Attr] & AM_DIR)) {  /* It is not a sub-directory and cannot follow */
                res = FR_NO_PATH; break;
            }
            dp->sclust = ld_clust(dp->fs, FATFS_DIR);
        }
    }
 
    return res;
}

I've checked the ff.cpp file with the old SDFileSystem (in which mkdir works) and this part is a bit different. Please see if you can resolve this. Let me know if you need me to debug further. Thanks

Hi Farzan. Sorry for the delay, I finally had a chance to look into this today. I set up a test jig using an LPC1768, and I still wasn't able to reproduce this issue using the test routine you posted. I see that FatFs has been updated to R0.11a. I'll submit a pull request to get FATFileSystem updated as well, it's possible that may resolve your issue.

19 Oct 2015

Neil Took your advice and success! managed to created a csv file on the SD card that opens in Excel and is perfect.. Thank you so much for your help, and especially your contribution to the mbed site, plebs like me really appreciate your efforts

Cheers Rudy

24 Nov 2015

Hi Neil, The library hasn't been updated since your last post. Any progress on that? I'm surprised that I'm the only one facing this issue. Any other suggestions on how to resolve / debug it?

24 Nov 2015

Farzan Hasani wrote:

Hi Neil, The library hasn't been updated since your last post. Any progress on that? I'm surprised that I'm the only one facing this issue. Any other suggestions on how to resolve / debug it?

Hey Farzan. Sorry, I've been a little swamped at work lately, and I forgot about this. I'll try and get a pull request done tomorrow. There's some mbed-specific tweaks that have to be done to the FatFs code that make updating it non-trivial. The only other thing I can think of is it could be a code page issue with long filenames. What are you using to format your SD card?

24 Nov 2015

I'm using a SanDIsk card with 8GB capacity, formatted using SDFormatter V4.0

24 Nov 2015

Farzan Hasani wrote:

I'm using a SanDIsk card with 8GB capacity, formatted using SDFormatter V4.0

Should be fine then... I've updated FATFileSystem to FatFs R0.11a, and submit a pull request over at GitHub. Once the devs to approve it, I'll update SDFileSystem as well. Hopefully that will fix your issue.

26 Nov 2015

Ok Farzan, I just updated SDFileSystem with the latest version of FATFileSystem based on FatFs R0.11a. The changelog lists some code page related bug fixes that may be the root of your issue.

08 Dec 2015

In light of some issues with FatFs and disk_sectors() and whatnot, I've modified the way card_type() works in the latest version of SDFileSystem. It will no longer attempt to initialize the disk under the table in order to return a valid card type. Therefore, both card_type() and disk_sectors() will only return proper values after the card has been mounted, either manually or automatically. To help offset this inconvenience, I've added another method called card_present() for checking whether or not a card is present in the socket. The updated SDFileSystem_HelloWorld program demonstrates card_present(), as well as the correct sequence for accessing card_type() and disk_sectors().

09 Dec 2015

Hi Neil, I just tested the mkdir function with the updated library. Still the same result as before. Any thoughts?

09 Dec 2015

Farzan Hasani wrote:

Hi Neil, I just tested the mkdir function with the updated library. Still the same result as before. Any thoughts?

Hi Farzan. I still haven't been able to reproduce your issue on my end, so at this point I'm out of ideas. Since it seems to be a FatFs-related bug, you might have more luck on the FatFs User Forum. I'll keep an eye out for it, and if it ever shows up on my end I'll let you know.

02 Feb 2016

Hi Neil and thank you for your job ! ;) I am a student who had already used mbed with a LPC1768 in simple project. I've got a new one where I need to write in a csv file but for now I am trying it in a text file.

I trying to use your library with your hello world example and a STM32F74 DISCOVERY assuming that :

MOSI=DI=CMD=PD_2 ; MISO=DO=DAT0=PC_8 ; SCLK=CLK=CLK=PC_12 ; CS= = DAT3=PC_11 ; CD= Card detector =PC_13 ;

I used this : https://learn.adafruit.com/downloads/pdf/adafruit-micro-sd-breakout-board-card-tutorial.pdf p8-9 ->spi http://elm-chan.org/docs/mmc/gfx1/micro_contact.jpeg spi->sd http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/DM00190424.pdf p24 sd->STM32F74

Unfortunately it doesn't work. I can compile but nothing happen. No text file in the uSD and pc.printf use with Serial usb doesnt print everything. Maybe I've got all wrong with my pins declaration ?

If you have a clue,or everyone else, I will be greatful. Thank you for your time and sorry for my english, that isn't my mother tongue :)

Thomas

13 Apr 2016

Hello Neil,

thank you for creating such an awesome library!

In one of my projects I do some research on how to log sensor readings to SD cards. I played around with the "default" SDFileSystem library and was able to write sensor data to a microSD card.

After inserting, removing and restarting over and over again the microSD card is damaged.

In your library I found

SDFileSystem::mount();
SDFileSystem::unmount();

functions.

I assume, this functions can be used for save mount and unmount the cards in terms of Windows "Save Remove Medium XY". Is this correct? I don't want to damage my new microSD cards.

Notes: My platforms are FRDM-KL25Z, FRDM-K64F and NXP LPC1768. As Frank Vannieuwkerke mentioned, compiler errors throws errors because the missing PullDown feature on the KL25Z. It is okay, I wont use CD Pin and commented out the PullDown code.

Kind regards, Tobias

13 Apr 2016

Tobias Knapp wrote:

Hello Neil,

thank you for creating such an awesome library!

In one of my projects I do some research on how to log sensor readings to SD cards. I played around with the "default" SDFileSystem library and was able to write sensor data to a microSD card.

After inserting, removing and restarting over and over again the microSD card is damaged.

In your library I found

1 2 SDFileSystem::mount(); SDFileSystem::unmount(); functions.

I assume, this functions can be used for save mount and unmount the cards in terms of Windows "Save Remove Medium XY". Is this correct? I don't want to damage my new microSD cards.

Notes: My platforms are FRDM-KL25Z, FRDM-K64F and NXP LPC1768. As Frank Vannieuwkerke mentioned, compiler errors throws errors because the missing PullDown feature on the KL25Z. It is okay, I wont use CD Pin and commented out the PullDown code.

Kind regards, Tobias

Hi Tobias, yes unmount() is the same is "Safely Remove" on Windows.

13 Apr 2016

Hey everyone, I've added basic support for high-speed mode (50MHz) to the latest version of SDFileSystem. Just specify a frequency >25MHz to the SDFileSystem constructor, and the library will automatically enable high-speed mode if possible. Technically this is available on SD cards that are v1.10 or later, but for now my library only supports it on cards that are v2.00 or later.

NOTE: Not all microcontrollers (or even certain pins on a particular microcontroller) are going to like clock rates >25MHz. For example, I had a hard time getting the LPC1549 to work with high-speed mode at just 36MHz. Also, the card's maximum current consumption can go up to as high as 200mA when high-speed mode is enabled.

19 Jun 2016

Hello,

I have a simple function for testing writing log data to a SD card.

Exact after 1368 time writing (append) a row to the SD card the software locks and after a hard reset everyting works fine.

I have try this 4 time's and everytime program stops after 1368 time append a string to the SD card. someone has a suggestion where it goes wrong?

I use controller LPC1549 on a own designed pcb.

Log function locks after 1368 writes (appends) to log file


SDFileSystem sd(SD_MOSI, SD_MISO, SD_SCK, SD_CS, "sd", P1_16, SDFileSystem::SWITCH_NEG_NC, 25000000);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SendLog(void)
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    u08 displayed = false;

    time_t seconds = time(NULL);

    // create an empty file pointer.
    FILE *myLogFile = NULL;

    if (!sd.card_present()) {            // Make sure a card is present

        Display_String("        No card present!        ",50,10); // Write string  on row 50 and column 10
        displayed = false;

        for (u08 teller = 52; teller<56; teller++)  {            // Deze regels clearen
            Display_String("                      ",teller,10);
        }

        sd.unmount(); // Unmount the SD card

        return;

    } else {
        Display_String("             Mounting SD card...",50,10); // Write string  on row 50 and column 10

        if (sd.mount() != 0) { // Mount the filesystem
            Display_String("failed to mount the filesystem! ",50,10);
        } else  {

            if(!(displayed))  {

                displayed = true;

                Display_String("        Mounting   OK           ",50,10);

                //Display the card type

                SDFileSystem::CardType cardType = sd.card_type();
                if (cardType == SDFileSystem::CARD_NONE)
                    Display_String("Card type: None",52,10);
                else if (cardType == SDFileSystem::CARD_MMC)
                    Display_String("Card type: MMC ",52,10);
                else if (cardType == SDFileSystem::CARD_SD)
                    Display_String("Card type: SD  ",52,10);
                else if (cardType == SDFileSystem::CARD_SDHC)
                    Display_String("Card type: SDHC",52,10);
                else
                    Display_String("Card type: Unknown",52,10);

                //Display the card capacity
                Display_Value_u32("Sectors: ", sd.disk_sectors(),53,10);
                PrintFF("Capacity (MB): ",((float)(sd.disk_sectors())/2048.0),54,10);

            }

            myLogFile = fopen("/sd/log.txt", "a");

            if (myLogFile == NULL) {  // check the file is open.
                Display_String("failed to open file!",55,10);
                myLogFile = fopen("/sd/log.txt", "w");
                return;
            }

            char day[25];
            strftime(day, 25,"%Y/%m/%d %a %H:%M:%S",localtime(&seconds));                  // Put Year, month, day, weekday, Hour, Minuts, Seconds in string
            fprintf(myLogFile,"\r\n%s %010lu %d %d %d ",day,test.ErrorStatus,200,300,400);  // write string, counter (test.Errorstatus) and 3 numbers on the SD card

            fclose( myLogFile); // Close logfile
        }
    }
    sd.unmount(); // Unmount the SD card
}

regards,

Rob Keij