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:

    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c
    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.c
    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.h

	FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c
	FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.c
	FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.h

The STM32F4 versions:

    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F4xx/NetworkInterface.c
    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F4xx/stm32f4xx_hal_eth.c
    FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F4xx/stm32f4xx_hal_eth.h

	FreeRTOS-Plus-FAT/portable/STM32F4xx/ff_sddisk.c
	FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.c
	FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.h

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 :

FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c

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.

Hein

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,
Nick

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 */
  } >RAM AT> FLASH

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.
https://github.com/0x4e/STM32F7/tree/master/Projects/FreeRTOS_9_0_Blinky_SystemView_Plus_TCP

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:
https://github.com/0x4e/FreeRTOS

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

Best regards,
Nick

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:

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?

    Drivers/STM32F7xx_HAL_Driver/src/stm32f7xx_hal_eth.c
    Drivers/STM32F7xx_HAL_Driver/inc/stm32f7xx_hal_eth.h

Otherwise there will be confusion.

I always use the following utility files:

../../FreeRTOS-Plus/Demo/Common/Utilities/printf-stdarg.c
Src/memcpy.c \

You will find them in the /labs release

I never really liked these ( HAL ) functions:

void SysTick_Handler(void)
{
	HAL_IncTick();
	 if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
	  {
	    xPortSysTickHandler();
	  }

}

__weak void HAL_IncTick(void)
{
  uwTick++;
}

/* And also  */

void vApplicationTickHook( void )
{
	/* Call the ST HAL tick function. */
	HAL_IncTick();
}

/* And also  */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

  if (htim->Instance == TIM13) {
    HAL_IncTick();
  }

}

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 e.eg 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,

Hein

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,
Nick

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!

Nick