简体   繁体   中英

MicroZed failing to write to SD card with xilffs library

I'm using a MicroZed dev board with a Xilinx Zynq 7010 and I'm trying to write to an SD card without any OS, just using the xilffs (LibXil fat file system) library.

In order to test it, I am using this xilffs_polled_example.c test file provided by Xilinx, but the test fails at this point:

// Write data to file.
Res = f_write(&fil, (const void*)SourceAddress, FileSize, &NumBytesWritten);
if (Res) {
    xil_printf("6: Failed to write data to file\n");
    return XST_FAILURE;
}

However, if I comment out that test the data verification test, then everything else is successful:

2: Successful mount
3: Successfully created FAT volume
4: Successfully opened file with permissions
5: Successfully put pointer at beginning of file
skip write test
7:Successfully put pointer back to beginning of file
8: Successfully read data from file
skip data verification
10: Successfully closed file

I thought it might be a problem to do with the SD card being in the wrong mode/format. I have formatted the SD card as FAT32 using Windows 10, and if the SD card was in read-only mode I think this test would also fail:

SD_File = (char *)FileName;
Res = f_open(&fil, (char *)FileName, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
if (Res) {
    xil_printf("4: Failed to open file with permissions\n");
    return XST_FAILURE;
}

Below is my code, it's basically the same as the linked file except for print statements to debug. Does anyone have any theories for what the issue may be?

int FfsSdPolledExample(void)
{
    FRESULT Res;
    UINT NumBytesRead;
    UINT NumBytesWritten;
    u32 BuffCnt;
    u32 FileSize = (8*1024*1024);
    //TCHAR *Path = "0:/";
    const char *Path = "0:/";

    Platform = XGetPlatform_Info();
    if (Platform == XPLAT_ZYNQ_ULTRA_MP) {
         // Since 8MB in Emulation Platform taking long time, reduced
         // file size to 8KB.
        FileSize = 8*1024;
    }

    for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){
        SourceAddress[BuffCnt] = TEST + BuffCnt;
    }

    // Register volume work area, initialize device
    Res = f_mount(&fatfs, Path, 0);
    if (Res != FR_OK) {
        xil_printf("2: Failed to mount\n");
        return XST_FAILURE;
    }
    xil_printf("2: Successful mount\n");

    // Path - Path to logical driver, 0 - FDISK format.
    // 0 - Cluster size is automatically determined based on Vol size.
    Res = f_mkfs(Path, 0, 0);
    if (Res != FR_OK) {
        xil_printf("3: Failed to create FAT volume\n");
        return XST_FAILURE;
    }
    xil_printf("3: Successfully created FAT volume\n");

    // Open file with required permissions.
    // Here - Creating new file with read/write permissions. .
    // To open file with write permissions, file system should not
    // be in Read Only mode.
    SD_File = (char *)FileName;

    Res = f_open(&fil, (char *)FileName, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
    if (Res) {
        xil_printf("4: Failed to open file with permissions\n");
        return XST_FAILURE;
    }
    xil_printf("4: Successfully opened file with permissions\n");

    // Pointer to beginning of file
    Res = f_lseek(&fil, 0);
    if (Res) {
        xil_printf("5: Failed to put pointer at beginning of file\n");
        return XST_FAILURE;
    }
    xil_printf("5: Successfully put pointer at beginning of file\n");

    // Write data to file.
    /*
    Res = f_write(&fil, (const void*)SourceAddress, FileSize,
            &NumBytesWritten);
    if (Res) {
        xil_printf("6: Failed to write data to file\n");
        return XST_FAILURE;
    }
    xil_printf("6: Successfully written data to file\n");
    */

    //Pointer to beginning of file .
    Res = f_lseek(&fil, 0);
    if (Res) {
        xil_printf("7: Failed to put pointer back to beginning of file\n");
        return XST_FAILURE;
    }
    xil_printf("7: Successfully put pointer back to beginning of file\n");

    //Read data from file.
    Res = f_read(&fil, (void*)DestinationAddress, FileSize,
            &NumBytesRead);
    if (Res) {
        xil_printf("8: Failed to read data from file\n");
        return XST_FAILURE;
    }
    xil_printf("8: Successfully read data from file\n");

    // Data verification
    /*
    for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){
        if(SourceAddress[BuffCnt] != DestinationAddress[BuffCnt]){
            xil_printf("9: Data verification failed\n");
            return XST_FAILURE;
        }
    }
    xil_printf("9: Data verification passed\n");
    */

    //Close file.
    Res = f_close(&fil);
    if (Res) {
        xil_printf("10: Failed to close file\n");
        return XST_FAILURE;
    }
    xil_printf("10: Successfully closed file\n");

    return XST_SUCCESS;
}

I stumbled upon the same problem in my design. Write function in xilffs appears to be broken.

Long story short, the problem is in diskio.c, it misbehaves during consecutive writes. Either card or DMA could still be busy, and the hardware wrapper functions never check'em to be free.

There is no good and stable solution so far, but adding usleep(200) before XSdPs_WritePolled() in disk_write() helps.

That's a BSP source, to edit it you need to make a local repository with your copy of xilffs, and add it to local repos list (xilinx tools -> repos), then edit diskio.c in local repo and regenerate bsp(s).

It appears the root of the problem is PS SD controller, which fails to correcly report its status while performing data transfers, and goes into unpredicted behaviour if asked for status too early. Simply waiting for 200us solves the problem, maybe waiting for interrupt can do so as well, but this is not tested.

Here's the patch for xsdps.c in sdps_v3_2, this one should be called less than delay in diskio.c in xilffs. Again, you need to fork xsdps lib to local repo to make it survive BSP regeneration. Keep in mind that it is NOT a solution, but just an unoptimal workaround.

*** D:/A15D/Vivado/A1550_Zynq/A1550_Zynq.sdk/local_repo/drivers/sdps_v3_2/src/a Wed Jun 14 05:24:28 2017
--- D:/A15D/Vivado/A1550_Zynq/A1550_Zynq.sdk/local_repo/drivers/sdps_v3_2/src/b Fri Aug 18 10:15:01 2017
***************
*** 87,92 ****
--- 87,94 ----
  #include "sleep.h"

  /************************** Constant Definitions *****************************/
+ #define CMD_TIMEOUT             200
+ 
  #define XSDPS_CMD8_VOL_PATTERN    0x1AAU
  #define XSDPS_RESPOCR_READY   0x80000000U
  #define XSDPS_ACMD41_HCS  0x40000000U
***************
*** 1066,1071 ****
--- 1068,1074 ----
        }
    }

+   usleep(CMD_TIMEOUT);
    XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CMD_OFFSET,
            (u16)CommandReg);

I didn't find that specific bug in zynq errata, but there are many other SD controller bugs, and all of them are marked as "won't be fixed because it's a 3rd party core". Quite a strange statement if you ask me, but let's leave it at that.

I will prbably dig further into case, and report here if anything notable arises.

Fixed the issue.

The 16GB Micro SD card that came with the MicroZed apparently doesn't work with this code. I swapped that SD card out for a cheap 1GB one that came with an old phone, formatted it the same way, and now the code works.

I'll leave the question open for anyone with an explanation as to what the problem is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM