FreeRTOS+TCP STM32H7 Setup

Hi all,

I’m porting FreeRTOS and FreeRTOS+TCP to a custom board with an STM32H7. I’m trying to get the Ethernet peripheral up, and I just had a quick question to try and point me in the right direction for troubleshooting.

I’m running on RMII. Should the ETH interrupt be firing while trying to probe PHYs, or is that only during actual communication? I’m seeing I2C activity on my scope on the MDIO/MDC lines, but not getting any PHYs enumerated, and the ETH interrupt isn’t firing.

I’m just curious if it should be, since that would really help point me in the right direction for getting this fixed.

Hello and welcome to the forum!

I do not have the hardware available right now to answer the question, but here are two sanity questions to ask (from the way you phrase your issue I am sure you have already checked this yourself, just to rule out the obvious):

  • have you also activated RMII in software?
  • Do the hardwired PHY address and the hardcoded PHY address in the driver match?

In my experience, one of the two accounts for about 90% of comm problems between the MCU and the PHY.

I am also curious about your usage of the terms “probing” and “enumerating.” Those imply that the driver would support PHY communicarion without a known address. I have not looked at the stock driver code recently, does it iterate through PHY addresses trying to detect a PHY on the RMII?

ST’s ethernet HAL stuff is all excluded from compilation. I’m using the modified driver from the FreeRTOS+TCP stack, but yeah, the RMII is all set in the generated stuff in stm32h7xx_hal_conf.h, which I think the FreeRTOS+TCP modified driver all tries.

Like I said, I can see the I2C comms, so clearly the FreeRTOS+TCP STM32H7 driver is initializing HW when I call FreeRTOS_IPInit.

I modified ST’s init code to just return; in the first user code block so that auto code generation doesn’t screw with me.

I am also curious about your usage of the terms “probing” and “enumerating.” Those imply that the driver would support PHY communicarion without a known address. I have not looked at the stock driver code recently, does it iterate through PHY addresses trying to detect a PHY on the RMII?

I put a scope on the I2C lines to the chip, and a breakpoint in xPhyDiscover’s loop. That function loops over looking at PHYs at addresses 0-31. On each attempt, I can see the I2C comms to the chip I’m using (KSZ8863RLL), but I just get 0s in IDs looking at the watch variables, so no valid PHYs found. I haven’t actually gone as far as logging and decoding what’s going on with the I2C bus. I just wanted to ask the question: Should the interrupt be firing at all at this point? Since I’m new to this chip and peripheral and figured that might be an obvious thing I’ve screwed up initing.

This could very easily be a hardware problem. It’s a brand new board. My main question was about whether or not I should be seeing that interrupt or not from the STM32 peripheral, so I could exclude it as the source of my problem.

As far as I know, the only interrupt from the PHY comes when the Link Status changes. That interrupt is not important when configuring the PHY.

Once the EMAC and PHY initialised, you can expect more interrupts from the EMAC/DMA: after reception and transmission.

This could very easily be a hardware problem

If this is a custom board, and if you have doubts about the wiring, I don’t mind having a quick look at the scheme, you can email it privately to me: hein [at] htibosch [dot] net

I uploaded a testing project for the STM32H747. Have you tested that in your hardware, or would that need too many changes?

The STM32H7 demo communicates through the “standard way”, i.e. using the EMAC and the RMII bus. Once all clocks were set, that worked immediately.

You are looking at I2C signals. Did you connect them as such? Have you enabled I2C Host mode by setting the right straps? Proper pullups?
Did you have a reason not to use the standard way, i.e. MII? For me that worked immediately.

@RAc wrote:

Do the hardwired PHY address and the hardcoded PHY address in the driver match?

It looks like @Mordkanin is using PHY port scanning from phyHandling.c. It tries all 32 addresses and it looks for a valid ID.

Thanks. I said ‘i2c’, but I really meant the native MDC management interface (Close, enough, right? Just faster and with a 32 pulse announce). Anyway, I found that the board house swapped an inductor and a capacitor of the same color, and nothing was working.

I’ve got the management interface up, interrupts seem to fire, but I can’t get a link properly established. Autonegotiation basically doesn’t work.

I’ve gotten FreeRTOS+TCP working on an STM32H7 disco board, but that was running a LAN8742A, and now I’m running a KSZ8863RLL, which is a 3 port device. Is anything addition needed when working with a device with multiple PHYs and a switch in it?

The FreeRTOS+TCP stack lists the KSZ8863 in its PHY discovery code, but I don’t see any examples of others using it to look for help on what might be different.

When I start up my code, this is what I get on debug:

xPhyReset: phyBMCR_RESET 0 ready
xPhyReset: phyBMCR_RESET 1 ready
xPhyReset: phyBMCR_RESET 2 ready
+TCP: advertise: 01E1 config 3100
+TCP: advertise: 01E1 config 3100
+TCP: advertise: 01E1 config 3100
prvEthernetUpdateConfig: LS mask 00 Force 1
xPhyStartAutoNegotiation: phyBMSR_AN_COMPLETE timed out ( done 0x02 )
Autonego ready: 00000006: full duplex 10 mbit high status
Network buffers: 56 lowest 56
Queue space: lowest 69
Link Status is high
IP Address: 192.168.5.3
Subnet Mask: 255.255.255.0
Gateway Address: 192.168.5.1
DNS Server Address: 8.8.8.8
xPhyCheckLinkStatus: PHY LS now 06
prvEthernetUpdateConfig: LS mask 06 Force 0
xPhyStartAutoNegotiation: phyBMSR_AN_COMPLETE timed out ( done 0x02 )
Autonego ready: 00000002: half duplex 10 mbit high status
Network buffers: 56 lowest 55

It detects unplugging/plugging the ethernet ports in just fine. The chip is strapped to be full auto negotiate on both ports.

Plugging into my PC set to auto, I get that. I tried turning off auto-negotiate on my PC, setting it to 10m/half, and weirdly the freertos console then says 10m/full.

Either way, autonegotiate always times out.

I’m sorry. I’m very slow at this. Piecing it together bit by bit…

One of the physical ethernet ports is hooked up wrong (Whoops!), but the other is correct, and still doesn’t work. I did notice as I start to dive that the KSZ8863 doesn’t actually support a soft reset, so the xPhyReset on them is entirely pointless.

Other than that observation, I really don’t know what I’m doing.

Plugging into my PC set to auto, I get that. I tried turning off auto-negotiate on my PC, setting it to 10m/half, and weirdly the freertos console then says 10m/full.

It looks like at least one of the ports is working properly.

Either way, autonegotiate always times out.

The PHY has 3 physical ports, have you connected every port to a PC or to a network switch? If not, negotiation will fail.

At this moment, the function xPhyStartAutoNegotiation() wants to negotiate with all (3) ports found.
These ports are represented with the bit masks 0x01, 0x02, and 0x04.
When ulDoneMask becomes 0x02, it means that the second port succeeded.

I am attaching a new version of phyHandling.c in which you can indicate which ports must be used. Please add to your FreeRTOSIPConfig.h:

#define  phyUSE_PORT_MASK    0x02U

With this macro, the function xPhyDiscover() will only discover and initialise a single port. Could you try that?

I expect the following logging:

  PHY ID xxxxx
  xPhyReset: phyBMCR_RESET 0 ready
  +TCP: advertise: 01E1 config 3100
  prvEthernetUpdateConfig: LS mask 00 Force 1
  Autonego ready: 00000004: full duplex 100 mbit high status
  Link Status is high

The driver needs some extension to handle multiple ports in a flexible way.
Will you use all 3 ports on your board?

Thanks. That really helps me understand how this is working much better.

My goal was for options for one or both of the ports to be plugged in. So I’ll need to extend some things to support that. Having just one on will certainly get me much further along, though, especially since the one port is hooked up wrong in hardware, anyway.

I don’t see an attachment, though.

Also, maybe you can help me understand: I know that it enumerates three PHYs, but only two of them are actual PHYs.

My goal here was to be able to use this chip as an ethernet switch, so while I only have one ethernet interface on my MCU, I would be able to have two ethernet ports on the hardware so that, for instance, I could chain multiple boards together.

So I’m digging a little deeper here. It looks like this won’t work without some more modification to the code. For one, MIIM register 31 on this chip doesn’t match what phyHandling.c expects.

You have to dive into the SMI 8 bit registers to get, for instance, the link speed. That’s not exposed in the MIIM status register. Not quite sure how to get the HAL to let me poke at those registers.

As a result, I don’t think this will ever configure the stm32’s ethernet peripheral properly to talk to port 3. So, I forced it to 100/full in prvEthernetUpdateConfig, but still no luck, so I’m currently looking to see what else might be different.

The chip itself is working as a switch. I got the other port working and have two PCs talking over it. Just can’t get the stm32 to do much of anything.

Ok. This has been quite educational for me. Nothing works yet, of course, but I’ve realized that this driver doesn’t seem to be set up for handling an ethernet switch like this chip.

I modified the phy handler to ignore ports 1 and 2, and just assume port 3 is always up and running at 100/full, which I believe is how this SHOULD be set up. I can’t actually look at the link status to port 3, unfortunately, since it’s hidden in a register that’s only available behind a different op code that it doesn’t seem like the STM32H7 ETH peripheral is capable of outputting to look at. I’ll either have to put the chip in I2C mode or SPI mode, which is gonna require a board redesign, to get to those registers.

Thoughts? I can tack on code later to look at ports 1 and 2 for informational purposes, but for now, running with a static IP, it doesn’t really seem to matter to my processor whether or not they’re actually connected. I am always connected to the switch. Everything available to me with PHYs 1 and 2 are mostly just “fyi” from my controller’s perspective, unless I want to actually intervene in how they negotiate links (Which i don’t. They handle themselves just fine, as near as I can tell from testing them operating as two ports on a switch).

@Mordkanin, sorry for the silence. I was busy with many things.

Have you found a workable solution already?

I have a hardware setup that uses a 3-port KSZ8863MLL PHY. Two ports are connected to the outside world.

Here is a scheme:

If it helps you, I will test phyHandler.c and try to get it running smoothly.

Hein

Yes, I got it working. Turns out I’m an idiot, and didn’t realize I had to set a bit in the last control register to turn on internal routing of the RMII clock for how I had the clock hooked up on the board.

That required disconnecting the SMC lines and bugging them into a free I2C port so I could send the command to set bit 3 in register 198. Apparently this might have been possible in other chips, but the H7’s ETH peripheral seems extremely limited to just the ‘standard’ stuff on its control lines.

I also overrode/deleted pretty much everything in the phy handling to just not do anything and always assume 100MB/full duplex is always up. Works like a charm.

I don’t get the impression that you are an idiot, after having solved all these issues :slight_smile:

Thank you for letting this know, it may help other developers with similar problems.

Thanks

1 Like