cancel
Showing results for 
Search instead for 
Did you mean: 

AZRTOS and FTP support

GreenGuy
Lead

STM32CubeIDE

Version: 1.14.1

STM32CubeMX - STM32 Device Configuration Tool

Version: 6.10.0-RC9

Build: 20231120-2037 (UTC)

OS: Linux (Mint 21)

I am trying to add support for FTP support using CubeIDE.  In the Software Packs Component Selector, under Network NetXDuo> NetXDuo> there are several Addons that can be applied.  One that I am currently using is Addons Web Server and that is working.  However, I do not see a selection for FTP.  I do find in the software packs repo for STM32H7 (version 3.2.0), in the Middlewares/ST/netxduo/addons folder another folder called ftp.  This folder contains the nxd_ftp_server.c and nxd_ftp_server.h files I need to support ftp service.  If I add those files to my project, in the same place the web addons are kept, when I regen the project the files I added are taken away.  It seems like there should be several more options available in the Software Packs selection so CubeMx knows to add them or at least not take them away. 

 

I guess for now, if have to put them in a safer location.  A little annoying.  

19 REPLIES 19

Hey GreenGuy,

thanks for the tip, but I'm using Microsoft Visual Studio with VisualGDB for the development. I probably will try to run a Linux box and test it with Konqueror.

I run Wireshark to check the telegrams and they're looking good until the STM32 just don't answer anymore and run into a timeout on which it drops the connection. I set breakpoints and stepped through the program, but it becomes very quickly super confusing. That whole FTP-Server packet is quite complicated and tricky to trouble shoot. 

I wonder what that default setting, you mentioned, could be.

One of the symptoms of not having sufficient memory available for NetX is that it simply stops working without somehow getting the message out that it ran our of resources.  This can be very difficult to determine in some cases which I have seen.  Sorry I don't have a magic bullet for you.  I can say that in CubeMX, after selecting system view and selecting the X-Cube-AZRTOS button under Additional Software and ten selecting the AzureRTOS Application tab in the Configuration window, the top items is Memory configuration and in there you can statically allocate how much memory each component will use.  I have 1024 * 150 for the NetXDuo memory pool size.  The suggested size was 120K when using the WebServer module.  The FTP thread, in my code, is using the NetX byte pool., so I increased the pool to 150K.  Yes it is a lot.  But my design has SDRAM and I am using some of it for the NetX byte pool so for me it is a small portion of the SDRAM.

 

You're exactly right, the AZRTOS software having a hard time to detect when it runs out of memory and reporting it. I noted already several times that it'll never check if there's enough memory available to do things and the CPU runs into the nirvana. Sure, the most functions return error messages pointing out that something went wrong, but many functions are so deeply stacked into each other that the original message gets lost when it returns back to the surface. However, I did the static memory allocation and assigned memory addresses to everything.

Here is an overview of my memory assignment:

I'm using a STM32H753ZI CPU which has this memory mapping:

MEMORY
{
  ITCMRAM (xrw)    : ORIGIN = 0x00000000, LENGTH = 64K
  FLASH (rx)       : ORIGIN = 0x08000000, LENGTH = 2048K
  DTCMRAM (xrw)    : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D1 (xrw)     : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)     : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)     : ORIGIN = 0x38000000, LENGTH = 64K
}

 

My ethernet Rx and Tx DMA descriptor arrays are defined like this:

// ETH DMA Descriptor structure definition
typedef struct
{
	__IO uint32_t DESC0;
	__IO uint32_t DESC1;
	__IO uint32_t DESC2;
	__IO uint32_t DESC3;
	uint32_t BackupAddr0; /* used to store rx buffer 1 address */
	uint32_t BackupAddr1; /* used to store rx buffer 2 address */
} ETH_DMADescTypeDef;

#define ETH_TX_DESC_CNT         8U  /* number of Ethernet Tx DMA descriptors */
#define ETH_RX_DESC_CNT         8U  /* number of Ethernet Rx DMA descriptors */

ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDescripSection"))); /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDescripSection")));   /* Ethernet Tx DMA Descriptors */

The memory allocation for the DMA descriptor arrays looks like this:

  /* ########################################################### */
  /*      definitions for tcp Rx and Tx -DescripSection          */
  /* ########################################################### */
  .tcp_sec 0x30000000 (NOLOAD) : {

    /* ETH DMA Descriptor Rx - 512 Bytes */
    . = ABSOLUTE(0x30000000);
    *(.RxDescripSection)

    /* ETH DMA Descriptor Tx - 512 Bytes */
    . = ABSOLUTE(0x30000200);
    *(.TxDescripSection)
  } >RAM_D2

 

 

My Byte Pool Buffer definitions for ThreadX, FileX, NetXDuo, HTTP-Server, and FTP-Server are like this:

#define TX_APP_MEM_POOL_SIZE                     1024 * 10
#define FX_APP_MEM_POOL_SIZE                     1024 * 10
#define NX_APP_MEM_POOL_SIZE                     1024 * 200

#define HTTP_SERVER_POOL_SIZE			8192
#define FTP_SERVER_POOL_SIZE			8192


#pragma region ***** ThreadX Pool Buffer definition *****
__ALIGN_BEGIN static UCHAR tx_byte_pool_buffer[TX_APP_MEM_POOL_SIZE] __ALIGN_END __attribute__((section(".TxPoolSection")));
static TX_BYTE_POOL tx_app_byte_pool;
#pragma endregion

#pragma region ***** FileX Pool Buffer definition *****
__ALIGN_BEGIN static UCHAR fx_byte_pool_buffer[FX_APP_MEM_POOL_SIZE] __ALIGN_END __attribute__((section(".FxPoolSection")));
static TX_BYTE_POOL fx_app_byte_pool;
#pragma endregion

#pragma region ***** NetXDuo Pool Buffer definition *****
__ALIGN_BEGIN static UCHAR nx_byte_pool_buffer[NX_APP_MEM_POOL_SIZE] __ALIGN_END __attribute__((section(".NxPoolSection")));
static TX_BYTE_POOL nx_app_byte_pool;
#pragma endregion

#pragma region ***** NetX HTTP-Server Pool Buffer definition *****
static uint8_t nx_http_server_pool[HTTP_SERVER_POOL_SIZE] __attribute__((section(".Nx_HTTP_ServerPoolSection")));
#pragma endregion

#pragma region ***** NetX FTP-Server Pool Buffer definition *****
static uint8_t nx_ftp_server_pool[FTP_SERVER_POOL_SIZE] __attribute__((section(".Nx_FTP_ServerPoolSection")));
#pragma endregion

The memory allocation for those Byte Pool Buffer looks like this:

  /* ########################################################### */
  /*   definitions for AZURE RTOS - ThreadX, FileX, NetXDuo      */
  /* ########################################################### */

  .azrtos_sec 0x30000400 (NOLOAD):
  {
    /* .TxPoolSection section - 10240 Bytes */
    . = ABSOLUTE(0x30000400);
    *(.TxPoolSection)

    /* .FxPoolSection section - 10240 Bytes */
    . = ABSOLUTE(0x30002C00);
    *(.FxPoolSection)

    /* .NxPoolSection section - 204800 Bytes */
    . = ABSOLUTE(0x30005400);
    *(.NxPoolSection)

    /* HTTP-Server pool section - 8192 Bytes */
    . = ABSOLUTE(0x30037400);
    *(.Nx_HTTP_ServerPoolSection)

    /* FTP-Server pool section - 8192 Bytes */
    . = ABSOLUTE(0x30039400);
    *(.Nx_FTP_ServerPoolSection)

  } >RAM_D2

 

 

I've defined an additional buffer in the memory domain 3, which I'm going to use as a display buffer:

#define LS_RES_X_PX			800
#define LS_RES_Y_PX			480
#define LS_MEM_POOL_SIZE	LS_RES_X_PX * LS_RES_Y_PX / 8 

UCHAR ls_byte_pool_buffer[LS_MEM_POOL_SIZE] __attribute__((section(".LS_PoolSection")));

  /* ########################################################### */
  /*   definitions for E-Paper screen buffer                     */
  /* ########################################################### */

  .EP_screen_buffer 0x38000000 (NOLOAD):
  {
    /* .EPsbPoolSection section - 48000 Bytes */
    . = ABSOLUTE(0x38000000);
    *(.LS_PoolSection)

  } >RAM_D3

 

 There're a few things which are not really clear in the AZRTOS documentation. 

The Ethernet Packet Pool. I've defined it like this:

#ifndef DEFAULT_PAYLOAD_SIZE
#define DEFAULT_PAYLOAD_SIZE      1536
#endif

#define NX_APP_PACKET_POOL_SIZE			((DEFAULT_PAYLOAD_SIZE + sizeof(NX_PACKET)) * 100)


	// Allocate the memory for packet_pool.
	if (tx_byte_allocate(byte_pool, (VOID **) &pointer, NX_APP_PACKET_POOL_SIZE, TX_NO_WAIT) != TX_SUCCESS)
	{
		Error_Handler(TX_POOL_ERROR);
	}

	// Create the Packet pool to be used for packet allocation,
	// If extra NX_PACKET are to be used the NX_APP_PACKET_POOL_SIZE should be increased

	if (nx_packet_pool_create(&EthPool, "NetX Main Packet Pool", DEFAULT_PAYLOAD_SIZE, pointer, NX_APP_PACKET_POOL_SIZE) != NX_SUCCESS)
	{
		Error_Handler(TX_POOL_ERROR);
	}

 

The Packet Pool Size for the HTTP-Server:

#ifndef NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE
#define NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE      600
#endif
#define HTTP_SERVER_PACKET_SIZE			(NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE * 2)
#define HTTP_SERVER_POOL_SIZE			8192


	// Create the server packet pool.
	ret = nx_packet_pool_create(&HTTP_ServerPool, "HTTP Server Packet Pool", HTTP_SERVER_PACKET_SIZE, nx_http_server_pool, HTTP_SERVER_POOL_SIZE);

	// Check for server pool creation status.
	if (ret != NX_SUCCESS)
	{
		Error_Handler(0xFF);
	}

 

The Packet Pool Size for the FTP-Server:

#define DEFAULT_MEMORY_SIZE				1024
#define FTP_SERVER_PACKET_SIZE			DEFAULT_MEMORY_SIZE * 1
#define FTP_SERVER_POOL_SIZE			8192


	// Create the server packet pool.
	ret = nx_packet_pool_create(&FTP_ServerPool, "FTP Server Packet Pool", FTP_SERVER_PACKET_SIZE, nx_ftp_server_pool, FTP_SERVER_POOL_SIZE);

	// Check for server pool creation status.
	if (ret != NX_SUCCESS)
	{
		Error_Handler(0xFF);
	}

 

These are my definitions which work somewhat. The HTTP-Server can't load all resources required for the web page, one file is always missing. I've to use the packed version of the web page, the HTTP-Server can't show anything from the unpacked version. I've attached both versions for you to have a look at. The FTP server can show the directory listings of the SD card, but as soon as I try to copy a file it just shows 100% but never actually copies anything and the directory listing fails from here onwards until I reset the CPU. I tried to step through the program but I always losing the breakpoint somewhere. It's like the program pointer jumps to an unknown position. It's very strange.

You might see something I have overlooked, but I don't see any solution. I'm playing with the thought of using a completely different controller and software. Maybe something Linux based.

Let me know what you think.

 

One thing you could do is to initialize the areas for the various byte pools to a known value like 5A,FE,DEADBEEF, what ever you like.  Then after it runs for a while, pause the debugger and look to see how much of the initialized portion still contains your known value.  I even schedule a routine that checks for how much of an area is still untouched as a runtime pool check.

Not sure myself, just asking, how is the payload related to the packet size?

 

 

Just curious.  What are the HTML file for in the packed and unpacked rar files you sent?  Was the supposed to be C code?

The HTML files are the content of the web page shown by the HTTP-Server. Those files have to be stored on the SD Card. I just posted them so you kind of get an idea of what I'm trying to do. I'm looking into the possibility of using freeRTOS because i found an example of an FTP-Server which seems to work. 

I actually did this to be able to check the memory usage, but it's not very useful. I'm using Microsoft Visual Studio with VisualGDB for the development, and this gives me a tool which is called "Embedded Memory Explorer". It shows a very detailed memory usage for all variables and threads.

Here is the general memory usage overview: 

Intector_0-1714593533075.png

 and this is a detailed view of the memory usage:

Intector_1-1714593826093.png

This tool is very good and helped me a lot in detecting memory issues.

 

Very similar to STM32CubeIDE Build Analyzer.  Only problem is that it is static.

Or is that a profile after running using TraceX?

Any port in a storm!

Intector
Associate III

I finally found the problem and got everything working. The problem is that I connected the SD-Card to SDMMC1 which is in the D1 Domain. I had the AZRTOS system as static allocation and placed it in the address range of the D2 Domain. The SD driver cannot access anything in the D1 Domain under these conditions.  

Intector_0-1714796274323.png

To solve the problem, I simply moved everything belonging to the AZRTOS to the D1 Domain.

This is my new memory assignment in the linker script:

MEMORY
{
  ITCMRAM (xrw)    : ORIGIN = 0x00000000, LENGTH = 64K
  FLASH (rx)       : ORIGIN = 0x08000000, LENGTH = 2048K
  DTCMRAM (xrw)    : ORIGIN = 0x20000000, LENGTH = 128K

  ETH_DMA (xrw)    : ORIGIN = 0x24000000, LENGTH = 1K
  AZRTOS (xrw)     : ORIGIN = 0x24000400, LENGTH = 236K
  RAM_D1 (xrw)     : ORIGIN = 0x2403B400, LENGTH = 275K

  /* RAM_D1 (xrw)     : ORIGIN = 0x24000000, LENGTH = 512K */
  RAM_D2 (xrw)     : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)     : ORIGIN = 0x38000000, LENGTH = 64K
}
...
...
...
  /* ########################################################### */
  /*      definitions for tcp Rx and Tx -DescripSection          */
  /* ########################################################### */
  .tcp_sec 0x24000000 (NOLOAD) : {

    /* ETH DMA Descriptor Rx - 512 Bytes */
    . = ABSOLUTE(0x24000000);
    *(.RxDescripSection)

    /* ETH DMA Descriptor Tx - 512 Bytes */
    . = ABSOLUTE(0x24000200);
    *(.TxDescripSection)
  } >ETH_DMA

  /* ########################################################### */
  /*   definitions for AZURE RTOS - ThreadX, FileX, NetXDuo      */
  /* ########################################################### */

  .azrtos_sec 0x24000400 (NOLOAD):
  {
    /* .TxPoolSection section - 10240 Bytes */
    . = ABSOLUTE(0x24000400);
    *(.TxPoolSection)

    /* .FxPoolSection section - 10240 Bytes */
    . = ABSOLUTE(0x24002C00);
    *(.FxPoolSection)

    /* .NxPoolSection section - 204800 Bytes */
    . = ABSOLUTE(0x24005400);
    *(.NxPoolSection)

    /* HTTP-Server pool section - 8192 Bytes */
    . = ABSOLUTE(0x24037400);
    *(.Nx_HTTP_ServerPoolSection)

    /* FTP-Server pool section - 8192 Bytes */
    . = ABSOLUTE(0x24039400);
    *(.Nx_FTP_ServerPoolSection)

  } >AZRTOS

 

Here are the adjustments for the MPU settings in the "main.c":

#pragma region ***** MPU configuration *****
void MPU_Config(void)
{
	MPU_Region_InitTypeDef MPU_InitStruct = { 0 };

	/* Disables the MPU */
	HAL_MPU_Disable();

	/* Initializes and configures the Region and the memory to be protected */
	/* default settings for the complete memory address range */
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER0;
	MPU_InitStruct.BaseAddress = 0x0;
	MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
	MPU_InitStruct.SubRegionDisable = 0x87;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER1;
	MPU_InitStruct.BaseAddress = 0x24000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER2;
	MPU_InitStruct.Size = MPU_REGION_SIZE_1KB;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER3;
	MPU_InitStruct.BaseAddress = 0x30000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER4;
	MPU_InitStruct.BaseAddress = 0x30002000;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER5;
	MPU_InitStruct.BaseAddress = 0x30004000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/** Initializes and configures the Region and the memory to be protected
	*/
	MPU_InitStruct.Number = MPU_REGION_NUMBER6;
	MPU_InitStruct.BaseAddress = 0x38000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/* Enables the MPU */
	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}
#pragma endregion

 

Also, I placed a public repo on GitHub which a complete functional example for the STM32H7 with AZRTOS, HTTP-Server with content from SD-Card, and FTP-Server to update the SD-Card content. I tested FileZilla in passive mode with binary file transfer which works great.

GitHub repo for STM32H7-AZRTOS example 

The memory has to be optimized because I used it very generous.