FreeRTOS +TCP on SAME70

Good Find! I have worked with the rev. B chips before and never could get them working, glad to see someone figured it out. I’m new to the thread, but I did find an example of rtos+tcp long ago on a forum. I noticed the link has since been broken and uploaded a copy to git:


It works on the ATSAME70-XPLD board, and uses RTOS 10.0.

Perhaps it may be useful,

I just received the following question about the SAME70 network driver:

have you been able (or tried) to use the +TCP implementation
with DCache enabled? I’m trying to use a UART DMA process
which relies on DCache, so it looks like I’ll need to get DCache
functioning with the +TCP stack.

Answer: both should be possible, with and without DCache.samE70_flash.ld.zip (2.0 KB)

I am attaching my “samE70_flash.ld”, which defines :

.first_data (NOLOAD) :
{
    . = ALIGN(4);
    _first_data = . ;
    *(._first_data ._first_data.*)
    . = ALIGN(4);
    _e_first_data = . ;
} > ram

at the very beginning of RAM. If I am not mistaken, that part of RAM has no caching.

So this should make it possible to enable data cache, while the +TCP driver still works.
Please verify if the beginning of RAM is really not cached.

A driver like Zynq also works well with cached memory: each time when memory is handed over from peripheral to host Xil_DCacheInvalidateRange() will be called.
When the host hands over RAM to the peripheral, Xil_DCacheFlushRange() will be called.

It is important that each object ( DMA descriptors and packet buffers ) has a length that is a multiple of a cache page, often 32 bytes:

__attribute__ ( ( aligned( 32 ) ) )   // align with DCache pages
__attribute__ ( ( section( ".first_data" ) ) )   // Allocate in the beginning of RAM
    uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ];

FWIW, we have been using SAME70Q20B with KNZ8081 phy and cache enabled for over a year. We define a non-cached area of memory in the MMU and allocate the DMA buffers in that. A complication is that the standard newlib supplied for ARM M7 chips is compiled with unaligned memory accesses enabled, but they are not allowed when the memory is set to non-cached, and memcpy in particular does unaligned accesses.

David, thanks for these insights. That may help others who are on the same path.

with KNZ8081 phy

That should be KSZ8081, I suppose?

A complication is that the standard newlib supplied for ARM
M7 chips is compiled with unaligned memory accesses enabled

As you have seen, the +TCP driver only does aligned access to memory that is shared with DMA.
Do you think that this may cause other potential problems?

Thanks again to Hein for the ongoing support with the SAME70. I’ve continued my efforts to get DCache() working with +TCP, but haven’t had any success thus far. Per Hein’s earlier post, I declare a non-cached region of memory in my linker script as follows:

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)     : ORIGIN = 0x00400000, LENGTH = 0x00200000
  ram (wrx)    : ORIGIN = 0x20400000, LENGTH = 0x00056800
  ram_nocache (rwx) : ORIGIN = 0x20456800, LENGTH = 0x9800
}

...

/* ethernet */
.ram_nocache (NOLOAD):
{
    . = ALIGN(4);
    _sram_nocache = .;
} > ram_nocache

An obvious difference between my current approach and Hein’s listed above, is that my non-cached memory allocation is at the end of the memory region, after the heap allocation, whereas Hein’s is at the start. Could this be causing me issues?

With the above memory definition in place, I construct the various network buffers in gmac_SAM.c with the (seemingly) correct memory allocation (showing 2 below as illustration) :

COMPILER_ALIGNED(8)
__attribute__ ((section(".ram_nocache"))) uint8_t ucNetworkPackets[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE];

COMPILER_ALIGNED(8)
__attribute__ ((section(".ram_nocache"))) static gmac_tx_descriptor_t gs_tx_desc[GMAC_TX_BUFFERS];

@dc42 I don’t suppose the above is similar to how you’ve got cache enabled and working with your SAME70?

You also need to set up that region of memory as non-cached in the MMU. You can find the code I use to do this at https://github.com/Duet3D/CoreNG/blob/dev/cores/arduino/Cache.cpp in function Cache::Initand the linker script is https://github.com/Duet3D/CoreNG/blob/master/variants/same70/linker_scripts/gcc/flash.ld. The main project is https://github.com/Duet3D/RepRapFirmware/tree/v3.02-dev.

Hi David,

Thank you very much for clarifying and providing your example code/project, it’s greatly appreciated. I believe I’ve accounted for the MPU/MMU in my project, as the non-cached region is configured as part my application’s init procedure. Apologies, I should have included this in my earlier post.

mpu.h:

#define ITCM_START_ADDRESS                  0x00000000UL
#define ITCM_END_ADDRESS                    0x003FFFFFUL
#define IFLASH_START_ADDRESS                0x00400000UL
#define IFLASH_END_ADDRESS                  0x005FFFFFUL

#define IFLASH_PRIVILEGE_START_ADDRESS      (IFLASH_START_ADDRESS)
#define IFLASH_PRIVILEGE_END_ADDRESS        (IFLASH_START_ADDRESS + 0xFFF)

#define IFLASH_UNPRIVILEGE_START_ADDRESS    (IFLASH_PRIVILEGE_END_ADDRESS + 1)
#define IFLASH_UNPRIVILEGE_END_ADDRESS      (IFLASH_END_ADDRESS)

/**************** DTCM  *******************************/
#define DTCM_START_ADDRESS                  0x20000000UL
#define DTCM_END_ADDRESS                    0x203FFFFFUL


/******* SRAM memory macros ***************************/

#define SRAM_START_ADDRESS                  0x20400000UL
#define SRAM_END_ADDRESS                    0x2045FFFFUL

/* Regions should be a 2^(N+1)  where 4 < N < 31 */
#define SRAM_FIRST_START_ADDRESS            (SRAM_START_ADDRESS)
#define SRAM_FIRST_END_ADDRESS              (SRAM_FIRST_START_ADDRESS + 0x3FFFF)          // (2^18) 256 KB

#if defined MPU_HAS_NOCACHE_REGION
#define SRAM_SECOND_START_ADDRESS           (SRAM_FIRST_END_ADDRESS+1)
#define SRAM_SECOND_END_ADDRESS             (SRAM_END_ADDRESS - NOCACHE_SRAM_REGION_SIZE) // (2^17) 128 - 0x9800 KB
#define SRAM_NOCACHE_START_ADDRESS          (SRAM_SECOND_END_ADDRESS + 1)
#define SRAM_NOCACHE_END_ADDRESS            (SRAM_END_ADDRESS )
#else
#define SRAM_SECOND_START_ADDRESS           (SRAM_FIRST_END_ADDRESS + 1)
#define SRAM_SECOND_END_ADDRESS             (SRAM_END_ADDRESS)                            // (2^17) 128 KB
#endif
/************** Peripherals memory region macros ********/
#define PERIPHERALS_START_ADDRESS            0x40000000UL
#define PERIPHERALS_END_ADDRESS              0x5FFFFFFFUL

/******* Ext EBI memory macros ***************************/
#define EXT_EBI_START_ADDRESS                0x60000000UL
#define EXT_EBI_END_ADDRESS                  0x6FFFFFFFUL

/******* Ext-SRAM memory macros ***************************/
#define SDRAM_START_ADDRESS                  0x70000000UL
#define SDRAM_END_ADDRESS                    0x7FFFFFFFUL

/******* QSPI macros ***************************/
#define QSPI_START_ADDRESS                   0x80000000UL
#define QSPI_END_ADDRESS                     0x9FFFFFFFUL

/************** USBHS_RAM region macros ******************/
#define USBHSRAM_START_ADDRESS               0xA0100000UL
#define USBHSRAM_END_ADDRESS                 0xA01FFFFFUL

My init.c file (relevant function shown):

/**
 * \brief Set up a memory region.
 */
static void _setup_memory_region( void )
{

	uint32_t dw_region_base_addr;
	uint32_t dw_region_attr;

	__DMB();

/**
 *	ITCM memory region --- Normal
 *	START_Addr:-  0x00000000UL
 *	END_Addr:-    0x00400000UL
 */
	dw_region_base_addr =
		ITCM_START_ADDRESS |
		MPU_REGION_VALID |
		MPU_DEFAULT_ITCM_REGION;

	dw_region_attr =
		MPU_AP_PRIVILEGED_READ_WRITE |
		mpu_cal_mpu_region_size(ITCM_END_ADDRESS - ITCM_START_ADDRESS) |
		MPU_REGION_ENABLE;

	mpu_set_region( dw_region_base_addr, dw_region_attr);

/**
 *	Internal flash memory region --- Normal read-only
 *	(update to Strongly ordered in write accesses)
 *	START_Addr:-  0x00400000UL
 *	END_Addr:-    0x00600000UL
 */

	dw_region_base_addr =
		IFLASH_START_ADDRESS |
		MPU_REGION_VALID |
		MPU_DEFAULT_IFLASH_REGION;

	dw_region_attr =
		MPU_AP_READONLY |
		INNER_NORMAL_WB_NWA_TYPE( NON_SHAREABLE ) |
		mpu_cal_mpu_region_size(IFLASH_END_ADDRESS - IFLASH_START_ADDRESS) |
		MPU_REGION_ENABLE;

	mpu_set_region( dw_region_base_addr, dw_region_attr);

/**
 *	DTCM memory region --- Normal
 *	START_Addr:-  0x20000000L
 *	END_Addr:-    0x20400000UL
 */

	/* DTCM memory region */
	dw_region_base_addr =
		DTCM_START_ADDRESS |
		MPU_REGION_VALID |
		MPU_DEFAULT_DTCM_REGION;

	dw_region_attr =
		MPU_AP_PRIVILEGED_READ_WRITE |
		mpu_cal_mpu_region_size(DTCM_END_ADDRESS - DTCM_START_ADDRESS) |
		MPU_REGION_ENABLE;

	mpu_set_region( dw_region_base_addr, dw_region_attr);

/**
 *	SRAM Cacheable memory region --- Normal
 *	START_Addr:-  0x20400000UL
 *	END_Addr:-    0x2043FFFFUL
 */
	/* SRAM memory  region */
	dw_region_base_addr =
		SRAM_FIRST_START_ADDRESS |
		MPU_REGION_VALID |
		MPU_DEFAULT_SRAM_REGION_1;

	dw_region_attr =
		MPU_AP_FULL_ACCESS    |
		INNER_NORMAL_WB_NWA_TYPE( NON_SHAREABLE ) |
		mpu_cal_mpu_region_size(SRAM_FIRST_END_ADDRESS - SRAM_FIRST_START_ADDRESS)
		| MPU_REGION_ENABLE;

	mpu_set_region( dw_region_base_addr, dw_region_attr);


/**
 *	Internal SRAM second partition memory region --- Normal
 *	START_Addr:-  0x20440000UL
 *	END_Addr:-    0x2045FFFFUL
 */
	/* SRAM memory region */
	dw_region_base_addr =
		SRAM_SECOND_START_ADDRESS |
		MPU_REGION_VALID |
		MPU_DEFAULT_SRAM_REGION_2;

	dw_region_attr =
		MPU_AP_FULL_ACCESS    |
		INNER_NORMAL_WB_NWA_TYPE( NON_SHAREABLE ) |
		mpu_cal_mpu_region_size(SRAM_SECOND_END_ADDRESS - SRAM_SECOND_START_ADDRESS) |
		MPU_REGION_ENABLE;

	mpu_set_region( dw_region_base_addr, dw_region_attr);

#ifdef MPU_HAS_NOCACHE_REGION
	dw_region_base_addr =
        SRAM_NOCACHE_START_ADDRESS |
        MPU_REGION_VALID |
        MPU_NOCACHE_SRAM_REGION;

    dw_region_attr =
        MPU_AP_FULL_ACCESS    |
        INNER_OUTER_NORMAL_NOCACHE_TYPE( SHAREABLE ) |
        mpu_cal_mpu_region_size(NOCACHE_SRAM_REGION_SIZE) |
        MPU_REGION_ENABLE;

    mpu_set_region( dw_region_base_addr, dw_region_attr);
#endif

It’s important to note that the above currently works, provided I don’t have CONF_BOARD_ENABLE_CACHE set. As soon as I define CONFINE_BOARD_ENABLE_CACHE in my conf_board.h file, +TCP no longer appears to work, and I’m no longer able to ping the board.