FTP server on Zynq: corrupted files

Hello,

I am working with the FreeRTOS+TCP and FreeRTOS+FAT on a Zynq platform, and when the size file is above 500 Kbytes the file stored into the RAM disk is corrupted.

If the received bytes are stored in a static local buffer that I have created to test, and then they are checked the data are right. In fact, if I create a file to write all this buffer, and after closing this file, I open it again and I read it, the data are right. But if I write the data as they are received (from my local buffer into a file), when the transmission finishes, the checking fails.

I have done a lot of tests during the last weeks, but I don´t find what happens. Any information will be appreciated.

I use SDK2019.1, FreeRTOS+TCP from FreeRTOSv202012.00-LTS (with BufferAllocation_1.c), IP protocols from FreeRTOSv202012.00 and FreeRTOS+FAT from FreeRTOS-Plus-FAT-191108a-MIT.

Other settings that I have used are:

#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 96
#define ipconfigNETWORK_MTU 1500

#define ipconfigFTP_TX_BUFSIZE ( 256 * 1024 )
#define ipconfigFTP_TX_WINSIZE ( 8 )
#define ipconfigFTP_RX_BUFSIZE ( ( 256 * 1024 ) - 1 )
#define ipconfigFTP_RX_WINSIZE ( 12 )

#define niBUFFER_1_PACKET_SIZE 1536

Regards.
Raul.

Raul, that shouldn’t be difficult to solve.

Please make sure that you’re using the latest sources and drivers.

FreeRTOS+TCP can be found here.
FreeRTOS+FAT is now stored here
The HTTP and FTP servers are stored here

For the Zynq 7000, I recently added a disk driver that allows to use drives bigger than 64 GB.

Normally I won’t reply on the forum by summing up all repo’s, but we did solve some problem specific to Zynq. I forgot where, possibly in the network interface.

… when the size file is above 500 Kbytes the file stored into the RAM disk is corrupted.

Is it more likely that a large file becomes corrupted, or does it always get corrupt?

Also: you provide RAM memory to the RAM disk. In this example I create a disk of 45 MB:

#define mainRAM_DISK_SECTOR_SIZE  ffconfigRAM_SECTOR_SIZE
#define mainRAM_DISK_SECTORS      ( ( 45U * 1024U * 1024U ) / mainRAM_DISK_SECTOR_SIZE )

static uint8_t ucRAMDisk[ mainRAM_DISK_SECTORS * mainRAM_DISK_SECTOR_SIZE ];
pxRAMDisk = FF_RAMDiskInit( mainRAM_DISK_NAME,
                            ucRAMDisk,
                            mainRAM_DISK_SECTORS,
                            mainIO_MANAGER_CACHE_SIZE );

Are you sure that the buffer ucRAMDisk is big enough to hold so many sectors?

If the received bytes are stored in a static local buffer that I have created to test, and then they are checked the data are right…

I read it 5 times but I get lost here…

Thanks for your quick response.

When the file size is higher than 500 Kb, the file is always corrupted.

The RAM disk parameters are to create a disk of 5MB and the max file size is about 4MB:


What I wanted to say in my previous message is that I have added some code in prvStoreFileWork() function to do some checks (see prvStoreFileWork.c)
prvStoreFileWork.c (4.1 KB) :

a.- Copy the read data from the socket into a “static uint8_t uc_buffer[BUFF_SIZE]” variable that I have created, where BUFF_SIZE is 5242880

b.- When the reception of the file finishes:

  1. Check the content of the “uc_buffer[]”, to validate it and it is right.

  2. Save the content of “uc_buffer[]” into a new file, and this file is right.

I am going to review if there are differences between the latest versions and the versions that we are using.

Thanks.
Raúl.

I just tested a RAM-disk and FTP on a Zynq 7000, but I did not see any corruption of data.
.
Using FTP, I sent a source file of 400KB, and a source file of 900KB to the RAM disk. My RAM-disk was created using the same parameters, totalling 5MB. After that, I FTP-ed the two files back to my laptop for comparison. They were equal to the originals.

Can I find your project on a public place like github?

Or can you do the same test as I did, using the original protocol drivers from here?

The application that I used for testing is located here. It is a Makefile project and it also has configuration files for Eclipse.
You might want to have a look at it FreeRTOS configuration files.

The biggest issue that we had in the past was cached memory in combination with DMA. But I assume that normal TCP and UDP work well for you?

Hello Hein,

I have updated my project with the latest sources of FreeRTOS+TCP, FreeRTOS+FAT and the HTTP and FTP servers with the links that you gave me in your previous responses.

But the problem persists, and now it does not depend on the file size and the file does not always get corrupted.

As an example of the multiple tests that I have done, the next table shows the results of sending file of different sizes through FTP to the server and downloading them to my laptop for comparison:

imagen

I have also reviewed the configuration files of your application, and I did the following changes in the FreeRTOSIPConfig.h file:

  • ipconfigFTP_TX_WINSIZE from 8 to 12
  • ipconfigFTP_RX_BUFSIZE from ((256x1024) -1) to (256x1024)
  • ipconfigTCP_FILE_BUFFER_SIZE from its default value (2048) to 8x1460

But the results are worst… it is almost impossible to get a test ok.

Before adding the FTP server, I implemented a TCP server that works as a Command Line Interpreter, so I suppose that the TCP works well.

You can find the project that I am using to these tests in ZynqProjects/ftptest_ps0 at main · raul-proj/ZynqProjects · GitHub

I am going to try to implement your project in our IDE (SDK 2019.1) and to test it, but I am very confused because I don´t know what else to do.

Thanks.

Raul

Raul, thank you for uploading the “ZynqProjects”. What I miss there is the Xilinx library project, the hardware platform project, and the FreeRTOS kernel.
Of course I complete the project, but I wonder if you have it ready somewhere?

When I played with @raul’s Zynq project, I had conflicts with FPU soft/hard:

ld.exe: error: ftptest_ps0.elf uses VFP register arguments, libxil.a(close.o) does not

I could only compile the project with a hard FPU defined. And then I thought of memcpy() and function parameters: both may use the big FPU registers to hold data.

Raul tested with configUSE_TASK_FPU_SUPPORT defined as 2, and he reported that the corruption is gone!

Now configUSE_TASK_FPU_SUPPORT=2 is a bit expensive: during every task switch, all FPU registers will be stored and restored. That gives unnecessary overhead.
If floating point is not important, one can choose for a soft FPU, or no FPU at all. In those cases, the FPU registers will not be used.

PS. I often use this memcpy(), which only uses normal CPU registers.

Hello Hein,

Thank for your help to solve this problem.
This afternoon I have tested to use the memcpy.c file that you told me (putting back configUSE_TASK_FPU_SUPPORT to value of 1) with a right result.

Now I have the solved problem by two different ways.
But after reading another post here, I have the following doubt: what is it the best solution to apply if I have not to use the floating point in my application?

Option 1.- Put configUSE_TASK_FPU_SUPPORT a value of 2
There is an unnecessary overhead to every task switch (you give the amount of 2 x 260 bytes in the mentioned post).

Option 2.- Use your memcpy.c implementation that it doesn´t use FPU registers.
We lose the performance of the GCC/Xilinx build-in memcpy() that you say “is really fast when it uses the FPU registers” in the mentioned post.

If we delete the compiler options of “-mfpu=vfpv3” and “-mfloat-abi=hard” that are set by the Xilinx SDK when a new project is created there are a lot of linker errors: “uses VFP register arguments” in library files. So, I would discard it as another option, because it is the similar to Option 2.

Any recommendation will be welcomed

Raul

Good that the corruption has gone. But I think that memcpy() is not the only user of FPU registers.
FPU registers can also be used to pass arguments to functions.

You must have seen the function portTASK_USES_FLOATING_POINT()?
When configUSE_TASK_FPU_SUPPORT is defined as 1, you can indicate which tasks need to store floating point registers.
It is all explained on this page.

About the compilation error:

ld.exe: error: ftptest_ps0.elf uses VFP register arguments

There are several places where -mfloat-abi is defined:

  • In the properties of ftptest_ps0 → C/C++ Build → Settings → ARM v7 gcc compiler → Miscellaneous → Other flags
  • In the properties of ftptest_ps0 → C/C++ Build → Settings → ARM v7 gcc linker → Miscellaneous → Linker flags

In 2 BSP Makefiles:

  • ZynqProjects\RTOSDemo_bsp\Makefile
  • ZynqProjects\RTOSDemo_bsp\ps7_cortexa9_0\libsrc\standalone_v5_3\src\Makefile

The locations may be different in your project.