FreeRTOS+TCP and +FAT drivers STM32F4 and STM32F7

heinbali01 wrote on Sunday, June 04, 2017:

Hi All,

New FreeRTOS+TCP and +FAT drivers for the STM32F4 and STM32F7.

You will find them in the next post because when opening this new topic, I see no attach button :frowning:

I used copies of the HAL library and put them as separate copies in the driver directories:



The STM32F4 versions:



So please include these two “portable” directories into the include search path using -I, earlier that the HAL include directory.

The EMAC and the SDMMC peripherals of the F4 and F7 are very similar. I changed identifiers and comments so that the drivers also look very similar.

The drivers have been tested by several people, but please test them for your self as well. I tested them my self by using the FTP-server: I copied 500MB on an SD-card, copied these files back to the host, and then compared the files.

In my STM32F7 project, caching is enabled. An F7 cache-line has a fixed length of 32 bytes, so try to align all buffers at 32 bytes.
For STM32F7 it is profitable to use BufferAllocation_1.c and use vNetworkInterfaceAllocateRAMToBuffers() as defined in :


The +TCP drivers are optimised for and tested as zero-copy drivers in both directions:

    #define  ipconfigZERO_COPY_RX_DRIVER   1
    #define  ipconfigZERO_COPY_TX_DRIVER   1

Also, all drivers are completely interrupt-driven.

Please give us feed-back about your experiences with the drivers, either on this forum or privately.

Regards, Hein

( find the attachment here. )

heinbali01 wrote on Sunday, June 04, 2017:

Now I do have an Add attachments button so here are the new +TCP and +FAT drivers for both the STM32F4 and STM32F7.
Do not hesitate to ask any questions about them.


heinbali01 wrote on Monday, June 05, 2017:

After more testing with ipconfigZERO_COPY_TX_DRIVER = 1, a possible bug became apparent.

Please make the following change in FreeRTOS_TCP_IP.c, around line 738 :

 /* For sending, a pseudo network buffer will be used, as explained above. */
     if( pxNetworkBuffer == NULL )
         memset( &xTempBuffer, '\0', sizeof( xTempBuffer ) );
         pxNetworkBuffer = &xTempBuffer;
         xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
         xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
+        /* A pseudo network buffer can not be released. */
+        xReleaseAfterSend = pdFALSE;

nerdineering wrote on Saturday, June 24, 2017:

Hi Hein,

Thank you for sharing your driver for the STM32F7.

I am trying to get FreeRTOS +TCP running on the STM32F769I-DISCO board, however a hard fault is raised after the code runs for a few seconds. I’m not really sure what the root of the problem is… That said, I would like to understand the sections attribute that you add within the NetworkInterface.c file (sorry if this is a basic question).

You have a comment saying:
/* Put the DMA descriptors in ‘.first_data’.
This is important for STM32F7, which has an L1 data cache.
The first 64KB of the SRAM is not cached. */

According to my .map file, the DMA descriptors are in >64kB (71,840 bytes):

 .igot.plt      0x0000000000000000        0x0 /usr/bin/../lib/gcc/arm-none-eabi/4.9.3/cortex-m7/fpu/fpv5-sp-d16/crtbegin.o

.first_data     0x00000000200118a0     0xbb00 load address 0x0000000008019fd8
 .first_data    0x00000000200118a0     0xbb00 build/NetworkInterface.o
                0x00000000200118a0                DMARxDscrTab
                0x0000000020011920                DMATxDscrTab
                0x000000002001d3a0                . = ALIGN (0x4)

.bss            0x000000002001d3a0     0x54e8 load address 0x0000000008025ad8

according to arm-none-eabi-nm -n STM32F769I_DISCOVERY.elf

20011890 D _edata
200118a0 D DMARxDscrTab
20011920 D DMATxDscrTab
200119a0 d ucNetworkPackets
2001d3a0 b __bss_start__

Does this look legit? Presumably there are no changes required to the linker file?
By the way, I have the following defines enabled in the FreeRTOSIPconfig.h file:

#define ipconfigZERO_COPY_RX_DRIVER			( 1 )
#define ipconfigZERO_COPY_TX_DRIVER			( 1 )

Best regards,

heinbali01 wrote on Sunday, June 25, 2017:

-> I am trying to get FreeRTOS +TCP running on the STM32F769I-DISCO board

Great, then we’re using the same board and this should be solvable.

You have a comment saying:

     /* Put the DMA descriptors in '.first_data'.
     This is important for STM32F7, which has an L1 data cache.
     The first 64KB of the SRAM is not cached. */

Sorry, my bad. I did not explain everything that I had done.
I created a new data section that comes before the normal .data and .bss section’s.

You can do that in your STM32F746xxx.ld linker script :

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.first_data)     /* .first_data sections */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */

When you recompile the project, you will see that the DMA-related buffers placed within the first 64KB data block:

20000000 D _sdata
20000000 d pucDMABuffer
20000200 D DMATxDscrTab
20000280 D DMARxDscrTab
20000380 d ucNetworkPackets

The driver is indeed supposed to be comfigured as a true zero-copy driver:

#define ipconfigZERO_COPY_RX_DRIVER         ( 1 )
#define ipconfigZERO_COPY_TX_DRIVER         ( 1 )

Please have a try and let us here.

nerdineering wrote on Sunday, June 25, 2017:

Hi Hein,

Thanks for the very quick and informative reply!

I have made the changes to the Linker script, however, I unfortunetly still have the same problem. I will need to spend some more time investigating why the code is crashing.

I’ve uploaded the project to Github, in case you’re interested.

To build the code using the makefile, you’ll also need to place a number of other directories containing FreeRTOS_9_0, FreeRTOS-Plus (which contains your driver) and SystemView (to debug using JLink). The source for this can be found under:

Thanks again for your help. I’m really hoping its a silly mistake :).

Best regards,

heinbali01 wrote on Monday, June 26, 2017:

Nick, I compiled your Makefile project successfully, but I must admit that I have never worked with SEGGER yet.

I tried to debug the project using openocd.exe but it doesn’t get far, it doesn’t even reach the reset handler:

  ldr   sp, =_estack      /* set stack pointer */

What I miss in your Makefile is creating a total listing ( LSS ), which you can make as follows:

OBJDUMP = arm-none-eabi-objdump

$(BUILD_DIR)/%.lss: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(OBJDUMP) -S $< > $@

The LSS file is useful to understand a HardFault: you can lookup any address. But it won’t help avoiding the crash.

It turns out that the linker flags weren’t correct for me: a non-thumb ( =ARM ) version of __libc_init_array was linked used, causing a crash.

See e.g. here

Also I needed a different .LD file for my board:

	#LDSCRIPT = STM32F769NIHx_FLASH.ld	# yours
	LDSCRIPT = STM32F746NGHx_FLASH.ld	# mine

Also I have to use a different version of port.c :

	#portable/GCC/ARM_CM4F/port.c		# yours
	portable/GCC/ARM_CM7/r0p1/port.c	# mine

I always advice to start testing a TCP application without DHCP:

    #define ipconfigUSE_DHCP    0

So at least you know which device to ping.

Would you mind to remove ( or rename ) two files from the HAL driver directories?


Otherwise there will be confusion.

I always use the following utility files:

Src/memcpy.c \

You will find them in the /labs release

I never really liked these ( HAL ) functions:

void SysTick_Handler(void)
	 if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)


__weak void HAL_IncTick(void)

/* And also  */

void vApplicationTickHook( void )
	/* Call the ST HAL tick function. */

/* And also  */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

  if (htim->Instance == TIM13) {


In my opinion, SysTick_Handler() is part of the OS and should not be overridden.

The function HAL_IncTick() will only increment a counter. Why not use the FreeRTOS tick-count?
Or some other timer, like this:

	#include "hr_gettime.h"
	uint32_t HAL_GetTick(void)
		uint64_t ullResult = ullGetHighResolutionTime();
        /* convert uS to ms. */
		return ( uint32_t ) ( ullResult / 1000ull );

What I can see is that my STM32F7 does not crash any more, and I can ping the device.
But I still haven’t tested everything.

Hope this helps for now,


nerdineering wrote on Monday, June 26, 2017:

Hi Hein,

Thanks once again for your help.
The program now runs and I can ping the board! In the end I had to disable the LCD driver in my “BSP_Config_Task”… I still do not know the exact cause, however, I have a feeling it is down to the way the HAL interferes with the SYSTICK. Therefore I’ll have a look at cleaning this up based on your recomendations.

Thanks also for the tip on creating the total listing. I have added the commands you have to my Makefile (very useful).

What I miss in your Makefile is creating a total listing ( LSS ), which you can make as follows:

OBJDUMP = arm-none-eabi-objdump

$(BUILD_DIR)/%.lss: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(OBJDUMP) -S $< > $@

The LSS file is useful to understand a HardFault: you can lookup any address. But it won’t help avoiding the crash.

Hopefully I will have time tomorrow evening to clean everything up and post the complete code via GitHub + some SystemView captures for anyone interested. :slight_smile:

Best regards,

heinbali01 wrote on Tuesday, June 27, 2017:

In the end I had to disable the LCD driver in my “BSP_Config_Task”…

I forgot to tell it, but I also disabled the LCD task.

PS. Some other tip for a Makefile :

    GCC_BIN    ?= C:/Ac6.v1.8/SystemWorkbench/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1.7.0.201602121829/tools/compiler/bin
    GCC_PREFIX ?= arm-none-eabi

    CC = $(GCC_BIN)/$(GCC_PREFIX)-gcc
    AS = $(GCC_BIN)/$(GCC_PREFIX)-as
    CP = $(GCC_BIN)/$(GCC_PREFIX)-objcopy
    AR = $(GCC_BIN)/$(GCC_PREFIX)-ar
    SZ = $(GCC_BIN)/$(GCC_PREFIX)-size
    OBJDUMP = $(GCC_BIN)/$(GCC_PREFIX)-objdump

The above helps me to remember which compiler I used for which project. Sometimes changing compilers will cause regression: a project that used to work wonderfully all of a sudden has a lack of RAM, or it just crashes. Now at least I can see that Ac6.v1.8 still worked well.

Beside your gcc options, I often include -fno-builtin. Sometimes a memcpy() or memset() are being replaced by inline code, which may cause a crash because of a bad alignment. When the compiler sees memcpy( &b, &a, 4), it may be tempted to replace this with a single 4-byte move, assuming that both a and b are well aligned.

If you’re interested in testing performance, here is an iperf3 server , along with some explanation.

Thanks for testing, and please let me hear how things are going. Regards.

nerdineering wrote on Tuesday, June 27, 2017:

Hi Hein,

I’ve updated the projects on git-hub with your suggestions.

Unfortunately I’ve not had a chance to delve into the issue with the LCD and also to test the performance using the iperf3 server. Hopefully, I’ll gain some time over the next week.

Thanks again for the help and insight!