FreeRTOS+TCP on SAM E5X

Hi! I would like to know if the FreeRTOS+TCP Network Interface driver has been ported to the Atmel SAME5X family of microcontrollers. I assumed not, at least not officially, since I could not find anything on this in the source files.

I stumbled upon 2 posts discussing this, but they are quite dated and one of the links that could have been the solution to this seems dead:
https://forums.freertos.org/t/tcp-support-for-microchip/7978
https://forums.freertos.org/t/porting-freertos-tcp-sam4e-demo-project-to-same54-project/7149

Is there an example out there of FreeRTOS+TCP working on SAME5X, or is there a guide on how to do this?

Regards,

P.-S.: On a side note, I’m messaging Microchip about their silicon revisions. On ALL SAM E5X 64 pins chips, silicon revision A does not have a working MAC. Stay safe, stay away from 64 pins SAM E5X chips :frowning:

If nobody replies with something already ported then you will find some porting docs here: https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_Porting.html

Thanks Richard.
The current ATSAM4E and DriverSAM ports are not very convenient to reuse, since they use old versions of Atmel’s ASF.
I’m going to try to create a simple SAM E5X port myself, starting without the zero copy stuff. Usually being an application developer, I’m slightly out of my depth.
It also doesn’t help that I won’t be able to test beyond compiling until Microchip provides me with good silicon versions or I switch to the SAM E54.

If someone works on this, please keep me in the loop, I’ll do the same here.
Cheers,

The current ATSAM4E and DriverSAM ports are not very
convenient to reuse, since they use old versions of Atmel’s ASF.

That is inherent to publishing device drivers: we must borrow some of the low-level drivers, and they tend to change continuously.

FreeRTOS+TCP not only borrowed the driver, it changed the way it functions, and it unified the drivers for SAM4E and SAME70.

Are there many differences between the GMAC of SAME5X and the GMAC of e.g. SAM4E?

I would recommend to start with a copy of the existing DriverSAM/NetworkInterface.c, and get it to work with a working GMAC driver for SAME5X.

You can always get help here in this post if you have questions. Good luck!

Thanks Hein, that helps getting me started on the right track.

After a few days of banging my head against the desk, I gave up porting the DriverSAM version. The ASF names and variables are a mess to translate from ASF3 to ASF4. That’s too much for me.

I instead followed the FreeRTOS+TCP porting guide. Luckily, Atmel / Microchip provides both MAC and PHY drivers, so implementing a simple NetworkInterface.c is simple enough.

I can not validate that this is working at this point, thanks to faulty ATSAME53 64 pins chips. I won’t be able to test until I send another board in production with the ATSAME54N20A, so that’s probably 3 weeks delay, plus whatever I’ll be busy doing in 3 weeks.

In the meantime, I leave the code here for anyone to comment, correct and optimize.

ATSAME5X NetworkInterface.c:
NetworkInterface.c (10.9 KB)

I do however have a few questions regarding the DriverSAM port:

  1. Why do we need to set the MDC clock divider?
  2. Is the EMAC handler asleep by default and only called when there is an event from the GMAC? I suppose in this case we register the callback to the GMACHandler to wake up the task?
  3. For a MQTT IoT application where I have under 30 sensors connected to this board, reporting once per minute, for this device in particular, is it worth trying to get a zero-copy driver to work? I should be pretty good at 10 mbps, and to save RAM I limit the MTU to the DHCP minimum (578?)

Hello Marc-Antoine,

Here a few comments about your NetworkInterface.c :

static void prvPHYKeepAliveHandlerTask( void * pvParameters)
{
// _HT_ I recommend not to make a separate task for checking the PHY.
//      Only one task should have access to the PHY (read/write).    
//      Also, as long as you device receives packets, you may assume that the
//      PHY status is high. It can be quite disturbing if you poll the PHY
//      **while receiving data**.


static void prvEMACDeferredInterruptHandlerTask( void *pvParameters )
{
// _HT_ In this task you can also check the PHY status regularly.
//      Just pass a different timeout value to ulTaskNotifyTake().


BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
                                    BaseType_t xReleaseAfterSend )
{
// _HT_ I assum that you are not using a zero-copy driver?
//      It does not make sense to send a packet as long as the Link Status is low
//      so I would test for it:

    if( phy_link_state == pdTRUE )
    {
        mac_async_write(&ETHERNET_MAC_0, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength);
    }

// _HT_ xNetworkInterfaceInitialise() is supposed to return pdPASS only if the EMAC is
//      initialised correctly, and when the PHY Link Status is high:

BaseType_t xNetworkInterfaceInitialise( void )
{
    ...
    return ( phy_link_state == true ) ? pdPASS : pdFAIL;
}

Answering your 3 questions:

  1. Why do we need to set the MDC clock divider?

To get a proper clock speed for the MDIO, I think.

  1. Is the EMAC handler asleep by default and only called when there is an event from the GMAC? I suppose in this case we register the callback to the GMACHandler to wake up the task?

Yes of cause, when an important ISR has happened, the network task should be woken up, just like you see here:

void xRxCallback( uint32_t ulStatus )
{
    if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
    {
        /* let the prvEMACHandlerTask know that there was an RX event. */
        ulISREvents |= EMAC_IF_RX_EVENT;
        /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
        vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
    }
}
Also I would let the task sleep for at most a second, so that the PHY link status can be checked.
  1. For a MQTT IoT application where I have under 30 sensors connected to this board, reporting once per minute, for this device in particular, is it worth trying to get a zero-copy driver to work? I should be pretty good at 10 mbps, and to save RAM I limit the MTU to the DHCP minimum (578?)

It doesn’t sound like it can be easily done, and for now you wouldn’t need a zero-copy driver. The latter is useful on a fast LAN, not when communicating with a server on the Internet.

1 Like

I got the NetworkInterface to kinda work with the ATSAME54N20A. I think I am facing a hardware issue, since no incoming packets are detected.

The DHCPDISCOVER packet goes out to the router, the router replies with DHCPOFFER, but GMAC_Handler() is never called. I checked the electric schematics and live signals on the scope, and everything seems fine up to pins PA12 and PA13 (RXD1 and RXD0). Interrupt register bit is properly enabled, and polling the PHY registers for errors says there are none. Does that kind of problem ring a bell?

The situation seems similar to the situation in post #8 here: ATSAME5x series Ethernet | AVR Freaks. However, since I now have a 100 pins chip, I should not have the problem… right?

In the meantime, here is the incomplete driver, I hope it gets someone a head start. It relies on ASF4 (Atmel start) MAC and PHY drivers and middleware. NetworkInterface.c (13.2 KB)

Edit: Yup, seems like I switched from the STM32 to the ATSAM a bit fast. I connected GCRS (PA16) to the PHY’s GCRS_DV, but Microchip decided to only connect GRX_DV (PC20) (see Table 24-1 of the datasheet). I’ll try to add a microwire and send news.

Edit 2: The mistake was made when I switched from 64 pins package to 100 pins package. In the datasheet, under Table 6-1: Multiplexed Peripheral signals, Note (6) says that GRXDV function on PA16 is only available on 64 pins devices. Oh well! (And I gave up on the microwire. I’ll be back in 2-3 weeks).

I can not see the entire driver, but I wonder if the hardware does have the MAC-address programmed, and also if it will receive packets for the broadcast address?

If you want, I will explain how to start using phyHandler.c. It is a generic PHY driver, used in many +TCP network interfaces. But that is of later care.

I’ll be back in 2-3 weeks).

See you then

Is it possible that you have an MII/RMII mismatch? Is the PHY address correctly used in the software?

Just a shot into the blue, I’m not familiar with the hardware. Sorry for the noise if this should be a poor shot.

Alright!

So in the end I started making a lot of changes to the board, so I ordered better microwire and Soldered the PHY’s CRS_DV to PC20 (took a few tries and some copper wick). After a bit of messing around, I got the DHCP to work (!!!)… on second try, meaning that the first DHCPOFFER is not detected, but the second one is and is followed by a DHCPREQUEST and a DHCPACK.

I put the full driver in a stripped-down Atmel-start project here: GitHub - ma-lalonde/ATSAME54N20A_FreeRTOS_Plus_TCP

I will be working on this project to get the driver “good enough”, with my planned test being to make it work with a mosquitto MQTT broker.

Hein, your help would be greatly appreciated to provide tips on performance, reliability and code quality, and to get me started with phyHandler.c, which I understand is preferred if I want this driver to make it to the main branch some day :slight_smile:

Soldered the PHY’s CRS_DV to PC20 (took a few tries and some copper wick)

You’re a brave man. I used to solder my self too, but as the years pass by, and the parts get smaller, I feel less confident.

on second try, meaning that the first DHCPOFFER is not detected

Can you describe the timing more or less? Between start-up, ask for offer, get a reply ( but not detected ), ask a second offer?
Maybe you can record some on WireShark?

I completed the driver and fixed some bug / performance issues with @htibosch 's help in private chat. It is now part of a pull request:

the demo project, also linked in be previous post, is here: GitHub - ma-lalonde/ATSAME54N20A_FreeRTOS_Plus_TCP

You’re a brave man.

Thanks, it’s a useful skill to have. Maybe some day I’ll be good enough at designing boards to not need it anymore :slight_smile:

Can you describe the timing more or less?

I fixed it, as mentioned in the test project’s log. I had enabled MAC frame filtering (“Copy all frames” off), but had not configured it. The DHCPOFFER was not received in the first few seconds after boot. The dd-wrt Syslog looked like:

[t+0] DHCPDISCOVER
[t+0] DHCPOFFER (192.168.1.141)
[t+5] DHCPDISCOVER
[t+5] DHCPOFFER (192.168.1.141)
[t+5] DHCPREQUEST (192.168.1.141)
[t+5] DHCPACK

I am 100% positive that properly configuring the filter (and/or disabling it) fixed that issue, but I can not explain why DHCP worked at all on second try.