Using FreeRTOS Plus to handle UDP communications on TI Hercules

There were a few of these that can be fixed by having the right defined variables. Your application will determine exactly how you are going to fix the problems you have encountered. Because I have no need for using TCP, and therefore by extension DHCP and other protocols, our solutions will be different.

MPU_xQueueCreteCountingSempahore is a function that I managed to resolve by going to FreeRTOSConfig.h and defining the following variables:

#define configUSE_COUNTING_SEMAPHORES 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1

Make sure that the definition is not changed elsewhere.

I believe that you should be able to do a search using CCS to find the other functions, but you should find them in os_mpu_wrappers.h If you ctrl+click on the declarations, it should guide you to where the definitions are, as well as give you an idea as to what variables need to be defined. Iā€™ll do some digging on my end and see if I can find the solutions for the other undefined symbols, but I know for sure that I did solve the counting semaphore issue. Iā€™m not so sure about the others at this point.

Note: In the end, have needed to write a dynamic memory allocation function to make the xQueueCreateCountingSemaphore function return no issues. Iā€™m having issues getting it to work though. We can collaborate on that when you get to that point.

xQueueReceive: I didnā€™t encounter this issue. This is likely because I am using the automatically generated HalCoGen files for FreeRTOS. For me, xQueueReceive in FreeRTOS_IP.c maps to MPU_xQueueGenericReceive. There are no defined variable fixes that I know of.

xQueueSemaphoreTake: originates from xSemaphoreTake in BufferAllocation_2.c (line231) For me this also maps to xQueueGenericReceive. Iā€™m not sure how to help there either, unfortunately.

xTaskGetCurrentHandle: I did have a solution for this one. In FreeRTOS.h, make sure that INCLUDE_xTaskGetCurrentTaskHandle is defined to 1, and in FreeRTOSConfig.h make sure that configUSE_MUTEXES is defined to 1.

@ajsmart92
Thanks for the comments re: FreeRTOS.h and FreeRTOSConfig.h. That resolved the issues you noted.

I also started with a FreeRTOS port generated by Halcogen. I have a clean compile of FreeRTOS v10.3.1 after updates that runs a simple two task demo okay.

Iā€™m currently chasing changes related to the random number marcos/functions needed for FreeRTOS+TCP. Iā€™d welcome any insights on that.

Do you have UDP and/or TCP running? If yes, can you share anything from your port of FreeRTOS+TCP?

Thanks again!

I do not have them running, but I do have a random number macro working that you can use:

This file is what I have been able to narrow down to the minimum number of macros that I need to define. I havenā€™t worked on it in a little while, so Iā€™m not confident that they all work. Iā€™m pretty sure that itā€™s a work in progress.

I canā€™t upload the file, but it is titled defineFuncs.c. In adding it to your projects, you will need to add some includes to header files, but after that, it should compile without issues. The work I have will be included in the next post.

The version in Halcogen had been updated by TI to support the MPU as the version in the FreeRTOS download doesnā€™t.

/*

  • defineFuncs.c
  • Created on: Mar 17, 2020
  •  Author: ajsmart
    

*/

#include ā€œFreeRTOS_IP.hā€
#include ā€œNetworkInterface.hā€
#include ā€œstdlib.hā€
#include ā€œos_task.hā€
#include ā€œstdint.hā€
#include ā€œemac.hā€

BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber )
{
srand(*pulNumber);
return rand();
}

//probably will need this though.
/* The Idle task is created using user provided RAM - obtain the
address of the RAM then create the idle task. */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
//statictask_t is a custom struct
StaticTask_t **taskBuffer;
taskBuffer = (StaticTask_t **) malloc(sizeof(StaticTask_t *));
ppxIdleTaskTCBBuffer = taskBuffer;
//stacktype_t = uint32_t
StackType_t **StackBuffer;
StackBuffer = (StackType_t **) malloc(sizeof(StackType_t *)); //128 is configMINIMAL_STACK_SIZE
ppxIdleTaskStackBuffer = StackBuffer;//configMINIMAL_STACK_SIZE;
//uint32_t allocation
uint32_t *taskStackSize;
taskStackSize = (uint32_t *)malloc(sizeof(uint32_t));
taskStackSize = configMINIMAL_STACK_SIZE;
pulIdleTaskStackSize = taskStackSize;
return; //
/
}

//I will need to write a function for this.
BaseType_t xNetworkInterfaceInitialise( void )
{
/* TC - MOVED MAC and PHY address from HL_sys_main.c to here. Iā€™m not sure where, if anywhere,
* PHY address is used.
*
* MAC address is a HACK. Copied from an LwIP project for RM57L.
* The LaunchXL2-RM57L board does not have an EUI ID ROM.
/
/
HT In stead of declaring a MAC-address here, you can use the macro ā€˜ipLOCAL_MAC_ADDRESSā€™. See FreeRTOS_IP_Private.h
It will be filled by FreeRTOS_IPInit() at start-up. */
uint8 emacAddress[6U] = {0x00U, 0x08U, 0xeeU, 0xFFU, 0x03U, 0x6CU};
// uint32 emacPhyAddress = 1U;

BaseType_t xReturn;

/* TC - Ethernet MAC initialization function EMACHWInit() provided by TI Hercules Halcogen */
/* _HT_ Mind you that xNetworkInterfaceInitialise() will be called repeatedly until it
returns pdPASS (same as pdTRUE).
So make sure that you call EMACHWInit() only once. It probably makes no sense to call it more
often. When the EMAC is initialised successfully, this function returns pdPASS only
when the Link Status is high, i.e. when the connection with the router or switch is OK.
*/
if ( EMACHWInit(emacAddress) == EMAC_ERR_OK )
{
    xReturn = pdTRUE;
}
else
{
    xReturn = pdFALSE;
}

return xReturn;

}

//I will need to write a function for this.
/* Send a network packet. The ownership will be transferred to
the driver, which will release it after delivery. /
/
The network driver is responsible for freeing the network buffer
after the packet has been sent. */
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend )
{
BaseType_t ret = 30; //typedef long
return ret;
}

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
//Nothing done in the other hooks, so I donā€™t think that we are going to do anything with the
//function here, but there may be something that we need to do later.
}

BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber )
{
srand(*pulNumber);
return rand();
}

Sorry, I accidentally pressed on REPLY. Please ignore this message.

This function:

 BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber )
{
    srand(*pulNumber);
    return rand();
}

is not how it was meant to be.

The function must return pdPASS if the random generator is operational. If there is a (hardware) problem, the function must return pdFAIL.

*pulNumber must be set in the function.

If you have nothing better than rand(), you can define it like this:

BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber )
{
	uint32_t ulR1 = rand() & 0x7fff;
	uint32_t ulR2 = rand() & 0x7fff;
	uint32_t ulR3 = rand() & 0x0003;
	*( pulNumber ) = (ulR1 << 17) | (ulR2 << 2) | ulR3;

	return pdPASS;
}

This implementation assumes that rand() returns a 15-bit random number.

Note that the AWS library has a much better implementation. Some MCU also have a random generator as a peripheral.

About srand() : please make sure that after every start-up of the device, a different sequence of numbers will be generated.

More randomness = more security.

1 Like

@htibosch Thanks!

Iā€™ve got past the random number problems for now. Iā€™ll clearly need to revisit this in more detail but I didnā€™t want it to block other work on FreeRTOS+TCP port.

Iā€™m now left with two errors:

undefined first referenced
symbol in file


MPU_xQueueReceive ./FreeRTOS-Plus-TCP/FreeRTOS_IP.obj

MPU_xQueueSemaphoreTake ./FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.obj

So, Iā€™m back to chasing them down. I still have much more to do in NetworkInterface.c so Iā€™ll try to figure this out in the background.

As alwaysā€¦ comments welcomed!

Iā€™m thinking that my remaining errors are due to the fact that I started with a TI Halcogen FreeRTOS v9.0.0 project and my updates to FreeRTOS v10.3.1 werenā€™t 100% complete.

In particular, based on @ajsmart92 comment earlier in this threadā€¦
ā€œFor me, xQueueReceive in FreeRTOS_IP.c maps to MPU_xQueueGenericReceive.ā€

ā€¦ and this postā€¦

I found that in my projectā€¦

xQueueReceive maps to MPU_xQueueReceive in os_mpu_wrappers.h but that os_mpu_wrappers.c implemented a function for MPU_xQueueGenericReceive (only).

Iā€™m trying to clean that up now.

Just confirming that did fix my errors related to MPU_xQueueReceive.

Now chasing the MPU_xQueueSemaphoreTake problem.

Continuationā€¦ Strangely, while os_mpu_wrappers.h has the following

#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake

ā€¦ there is no function for MPU_xQueueSemaphoreTake in os_mpu_wrappers.c

So thereā€™s the problem!

Continuedā€¦ I added a function for MPU_xQueueSemaphoreTake and that resolved the final error.

Back to work on NetworkInterface.c ā€¦ more to do.

Continuedā€¦
FYIā€¦ Iā€™ve reached the 3 consecutive post limit for the forum so I have to post updates by editing my last post.

I reviewed my files to see which, if any, FreeRTOS files were still remaining from the v9.0.0 version produced by Halcogen vs. my port of v10.3.1. There are threeā€¦

os_mpu_wrappers.c
os_port.c
os_portasm.c

Unfortunately, these are all in the portable directory of FreeRTOS and there is no pre-existing versions (that I know of) for v10.3.1. So, I kept them.

The recent issues Iā€™ve been having with os_mpu_wrappers.c are a reminder that I should expect these stale files to be a potential source of problems as I work on the port of FreeRTOS+TCP.

UPDATE April 9 PM ā€¦ appending due to 3 reply limitā€¦

Iā€™m confused on the Rx process. What I was expecting is that EMAC Rx triggers DMA that move moves Rx data into memory. Then DMA interrupts and a deferred ISR (task) processes the buffers to validate and extact packets.

But Iā€™m getting lost. Part of the problem of course is that I donā€™t have the advantage of an exisitng port for the Hercules RM57L. This causes another problem in that I have had to look a ports on other platforms.

I have a TI Halcogen HL_emac.c (driver) that provides an extensive set of functions. Iā€™ve been able to figure out how to use many of these functions but Iā€™m simply lost on the Rx side. Iā€™m expected to have to have an ISR that triggers a deferred ISR task.

Any pointers/hints welcomeā€¦ high-level. Doesnā€™t have to be a tutorial, I just need a treasure map!

UPDATE April 10 - AM ā€¦ appending due to 3 reply limit

I think this is what I was looking for (from the prvEMACHandlerTask)ā€¦

    if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )   /* TC - RX, TX, or ERROR event */
    {
        ulISREvents &= ~EMAC_IF_RX_EVENT;

        xResult = prvNetworkInterfaceInput();
        if( xResult > 0 )
        {
            while( prvNetworkInterfaceInput() > 0 )
            {
            }
        }
    }

Update from my end: Iā€™ve had other projects take the bulk of my focus since weā€™ve talked last, but I will be able to work more on this issue in the coming week. I found an issue with some emac functions that leads to dataAbort errors. This will likely prove useful as we get the transmit functions working well.

http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/455737?EMAC-TMS570LC4357-data-Entry-problem#pi320995filter=all&pi320995scroll=false

I considered the advice from @htibosch to use phyHandling.c carefully. But in the end I felt more comfortable mapping to the TI Halcogen generated code. So thatā€™t the path Iā€™ve been going down.

Iā€™m very close to completing an iteration of NetworkInterface.c code but a long ways off from having something that has been tested and works. Iā€™ve had to guess at a bunch of stuff contained in other examples of NetworkInterface.c. Weā€™ll see.

Iā€™ll post the code here when Iā€™m done installing all of my bugs! :grin:

Itā€™s taken me quite a while to make my way through network initialization for the Hercules RM57L. I had difficultly understanding the design intent and function of TI Halcogen code vs. the various examples of FreeRTOS+TCP.

Iā€™m now trying to piece things together and I find myself getting lost trying to understand how NetworkInterfaceInitialise() gets called the first time.

I see from examples that main.c has a call to FreeRTOS_IPInit() before the scheduler is started. But I then get lost.

Can anyone give me a high-level overview of how NetworkInterfaceInitialise() gets called for the first time?

Sure, via prvProcessNetworkDownEvent()ā€¦ but conceptually, Iā€™m not getting how that function gets triggered to start things up.