modm: Ethernet freertos_tcp on f439zi nucleo not working
Hello, I will append my experience here, even though there is an issue for that already:
Preamble
I got @mikewolfram 's lan8720a
phy driver and the corresponding example (using freertos_tcp) working with the f767zi nucleo board after changing some of the PHY pins hardcoded in the example he gave.
Getting There
After that, I tried to get it running on the f439zi but was unable to do so. After some hours of experimenting with the freertos network scheduler (RTOS_IP) and ethernet stack, i finally ended inside the event loop (controlled by freertos ip stack) of the lan8720a
(see here) which should eventually handle arp requests coming from another laptop connected to the board via ethernet.
The Problem
The event loop handles events constantly (as expected), but every event is regarded as a NOP modm::platform::eth::Event::None
and therefore ignored. Which means that the feeding function, responsible for setting proper events, is not working properly.
As it turns out, the producer function is this ISR
MODM_ISR(ETH)
{
using modm::platform::eth;
using modm::ethernet;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
EMAC::InterruptFlags_t irq = EMAC::getInterruptFlags();
EMAC::acknowledgeInterrupt(irq);
if (irq & (eth::InterruptFlags::Receive | eth::InterruptFlags::ReceiveBufferUnavailable)) {
ethernet::isrEvent |= eth::Event::Receive;
if (ethernet::emacTaskHandle) {
vTaskNotifyGiveFromISR(ethernet::emacTaskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
if (irq & (eth::InterruptFlags::Transmit)) {
ethernet::isrEvent |= eth::Event::Transmit;
if (ethernet::emacTaskHandle) {
vTaskNotifyGiveFromISR(ethernet::emacTaskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
if (EMAC::getInterruptFlags() & eth::InterruptFlags::AbnormalIrqSummary) {
// not used yet
}
}
My test have shown (led blinky, event chain debugging) that this specific ISR is not called properly. Is there something you guys can tell me about the differences between the interrupt handling (mainly ethernet-DMA interrupts) ?
Other Stuff
- I tried checking registers for interrupts, dma and others to see if any flags have changed but it seems that these chips(f4 & f7) are equal in that matter
- we have an internal issue where this errata was evaluated, but we could not find anything in particular which could be problematic: https://www.st.com/resource/en/errata_sheet/dm00068628-stm32f427437-and-stm32f429439-line-limitations-stmicroelectronics.pdf
End
Thank you for reading, maybe someone can help
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 31 (21 by maintainers)
I feel your pain… It could be possible the ethernet DMA for the F4 if unable to operate in the ‘modm_fastdata’ section of memory. In modm_lan8720a.cpp - edit this:
to this
Let me know if that fixes your issue…
Reading your posts about the .fast_data section reminds me, there was a comment in the original STM32 HAL implementation:
Good finding and sorry, I didn’t add it to the first implementation. Since I’m on a F7 and had no access to an F4 for testing I skipped all non-F7 specific code at that time.
I was mainly thinking about modm’s use of protothreads and resumable functions, where the stack doesn’t really exists and is continously changed under the hood.
For FreeRTOS it’s different, since the stack remains untouched IFF you wait synchronously for the DMA transfer to end. In general though, I’m not sure what guarantees C/C++ gives about stack memory lifetimes.
Regardless, only the main stack (which is not a FreeRTOS thread!) is allocated in the CCM, all other stacks are either dynamically allocated in heap, or statically (by modm::Thread) in main SRAM DMA-able memory.
I am however open to changing the main stack placement, but for CCM the access speedup is >2x compared to SRAM, therefore I placed it there by default.
You really have to go out of your way to allocate something in fastdata, which is why this is a very confusing to me.
scons listing
will give you a map of what objects are placed in.fastdata
etc.It’s simple, in C++ terms objects of automatic storage duration (that is all local objects not declared as
static
,extern
orthread_local
) live exactly as long as the enclosing code block.It’s shamefully hardcoded inside the linkerscripts in the heap table (in manually translated binary format even!!!). This needs to be extracted into modm-devices ideally. https://github.com/modm-io/modm/blob/develop/src/modm/platform/core/stm32/linkerscript/stm32_dccm.ld.in#L59-L68
I think I would consider it useful to give the modm:platform:cortex-m module an option not to create the stack in non-DMA memory, and probably even enable it by default. (As far as I know the stack is also in SRAM by default on other toolchains (ST-Cube…)). If you want to have the additional performance of TCM/CCM for your stack you can enable this option and should be aware of the disadvantages.
A broader use of DMA probably brings more advantages in total than having the stack in TCM/CCM. When I look at DmaSpiMaster (which has recently become available on many more devices) it is (unfortunately) very easy to run into the same problem there unknowingly.
I mean, we could have a debug assertion in the DMA driver to check the address range at runtime. The information is currently not part of modm-devices, but it’s not difficult to add. It’s probably the best quick hack that we can add.
Edit: Of course that only works if you use the DMA driver, a stand-alone attribute function is probably still better in general.
No, it’s 64kB of single-cycle access SRAM (but only from the CPU) it would be very wasteful to ignore that.
I don’t understand it either. Only the main stack, the fastdata and the heap0 is located in CCM. Is there something getting DMA’d from the main stack?
The linkerscripts are all specifically designed so that the “normal” data sections (.bss, .noinit, .data) are in main SRAM which is always DMA-able. Same goes for the heap. Only on devices that have a “fast” memory, like CCM on STM32F4 or TDCM on STM32F7, the data section
.fastdata
is placed there, otherwise it is also placed in main SRAM.So there should be no surprises like this at all if you don’t use any memory attributes, but if you use any memory attribute like
.fastdata
it can lead to weird results, depending on the family and even on the DMA instance.We need to document this better, since we’re starting to look into DMA now more and this very annoying to debug.
For the heap there are these MemoryTraits that you can use to get memory with extra traits. But you need to specifically request it, by default only DMA-able memory is allocated.
This is also how can allocate memory on the external heap (16MB on the STM32F469 Discovery for example).
@rleh I can do that, give me some days to do other stuff first 😄