uip demo for gcc: status, emac isr woes

rainer32 wrote on Monday, April 24, 2006:

I mentioned that i’d like to see the FreeRTOS uIP demo for at91sam7x (directory Demo/uIP_Demo_IAR_ARM7) work with plain gcc instead of iar.
So after some fumbling and googling around, i got all issues about the SAM7 uIP demo with gcc cleared out but one (with the emac isr, see below).

- About the headers: My preference was to get things to build with unified unaltered Atmel headers (I assume that’s what the IAR version uses anywas). As it turns out, the headers work fine with gcc: after running indeed into a couple problems myself with the inline functions instead of macros in lib_AT91SAM7X256.h and quite some googling, i found that the following does the trick:
- in order to avoid double defs errors, i added this line in FreeRTOSConfig.h: #define __inline inline static
- no such things as -Wstrict-prototypes, -Wmissing-prototypes and -Wmissing-declarations in the CFLAGS. Indeed, the first hates function pointers as arguments (lots! of warnings), the other two fill screens! of stupid warnings because lib_AT91SAM7X256.h has thousands of lines of inline functions without prototypes. I left a -Wextra in there though, although this gives lots of “unused parameter ‘null’”  warnings becaused of unfinished macros/inlines in lib_AT91SAM7X256.h, but i felt that this option covers so many different warning types that i’d be hesitant about taking it out.
- I did put back the first argument to AT91F_AIC_ConfigureIt in the calls (even though Richard pointed out it’s redundant), so as to stick with unified atmel headers.
- include lib_AT91SAM7X256 in Board.h as in the uIP/IAR demo, not ioat91sam7x256.h as in the lwIP/Rowley demo
- no intrinsic.h in FreeRTOSConfig.h line 33 for gcc
With that, the stock Atmel/IAR headers work with plain gcc just fine

- a couple typo/letter case stuff i ran into: i already mentioned “Board.h” in FreeRTOSConfig.h line 34 and “Emac.h” in EMAC/SAM7_EMAC.h line 74. Here are a couple new ones I ran into since: “Board.h” (should be upper case) line 35 of ParTest/ParTest.c, “uIP_Task.h” line 69 of main.c, and another one (though not directly related to the build process) on http://www.freertos.org/portsam7xiar.html, where it speaks of Demo/uIP_Demo_IAR_ARM7/uIP/uipopts.h. The actual name of the directory is ‘uip’ (all lowercase) and the filename uipopt.h (not uipopts.h). Still about that web page: it says something about how to use rmii (rather than mii). I remember reading in the at91.com forum that as per the atmel errata, rmii has bugs in the at91sam7 emac and is thus no longer supported. Still a possible typo, although this time an absolutely harmless one: in the Makefile of the lwip/rowley demo, theres many times “DEMO_APP_THMUB_xyz” (with THMUB instead of THUMB). i took the liberty to change that to DEMO_APP_THUMB_xyz

- by the way, i noticed that in the lwip demo, there’s a “static xSemaphoreHandle xSemaphore = NULL;” defined both in SAM7_EMAC.c and SAM7_EMAC_ISR.c, which thus will probably be a different variable in both files. Dunno if that’s a problem, just thought i should point it out.
- also, in uip/uipopt.h, there’s an U behind every octet for UIP_IPADDR[0…3], but not for UIP_NETMASK[0…3] or UIP_DRIPADDR[0…3] - strange?
- The Makefile is based on that from the Rowley/lwIP demo. I renamed it from ‘makefile’ to ‘Makefile’ though, as it’s the usual notation and there’s a line “touch Makefile” in the “clean” target. Note that this typo doesn’t even throw an error on posix systems (as make also accepts makefile and the touch command will touch or create an empty Makefile file), but I guess ‘Makefile’ was what’s intended (and windows just makes no difference and no empty Makefile but touches makefile). Actually, I like “clean” to remove all built objects rather than just touching the Makefile, but i guess under windows without cygwin, the ‘rm’ command might not be known by the system, so throw that line (and the editor bkpfile cleaning find/rm *~ line) out if you have troubles with it

anyways, back to the build and source:
- i took the boot.s, atmel-rom.ld and Cstartup_SAM7.c from the FreeRTOS lwIP/Rowley demo.
- in port.c (which i copied from …/…/Source/portable/GCC/ARM7_AT91SAM7S/port.c), i put AT91C_BASE_AIC as a first argument to AT91F_AIC_ConfigureIt (as in the iar version)
- i commented out the vEMACISR function from SAM7_EMAC.c since it’s arm code and won’t compile with the thumb rest in gcc. I’m no expert at that, but afaik, gcc has no such __arm thing and wants those things compiled separately and then linked together with thumb interwork options (correct me?). anyways, i believe that’s also how the rowley/lwip demo does it.
- by the way, in …/…/Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h, there might be a braces issue around lines 196 to 198 (i moved that opening brace from 196 to below 198). Depending on the choice of emac code, we don’t need that file. but please have a look at that brace anyways.

Ok. now we are at a point where the only thing that’s still missing or quirking is the emac isr code.
I tried 3 options (i made different Makefiles, just softlink or copy your choice to Makefile), but unfortunately all 3 options lead to the same problem: it builds fine, it runs fine after flashing it to the board as long as no ethernet packet comes, but when a packet comes, it freezes hard (probably not just the ip stack but the whole FreeRTOS, since the leds  freeze in their current state and stop blinking)

Before laying out what these options were, i’d like to point out that obviously precautions about emac isr and context switching are obviously done differently between the iar and gcc versions. the IAR version has an assembler wrapper, while the gcc version has a call to portENTER_SWITCHING_ISR. i tried it in that way (portENTER_SWITCHING_ISR instead of assembler wrapper, but i might have done something wrong here) and defined vEMACISREntry as vEMACISR in FreeRTOSConfig.h. also, the two versions differ in names such as portEXIT_SWITCHING_ISR vs portEND_SWITCHING_ISR (what’s the difference between those two?) for some options i had to define (copy/paste) portEND_SWITCHING_ISR. i did that in FreeRTOSConfig.h for now (though i’m aware that this is certainly not the right place to leave it)
So anyways, i temporarily renamed the EMAC dir from the uip/IAR demo to EMAC_uip_iar_modified and copied the EMAC dir from the lwip/rowley demo as EMAC_lwip_rowley_modified, so you can easily see which options takes which files from what code.

So here for Option 1:
- i took the vEMACISR code had thrown out of the iar version of SAM7_EMAC.c and put it into a file SAM7_EMAC_ISR_alt.c. i added the portENTER_SWITCHING_ISR() call at the beginning of that function in hope that this would take care of the isr context switching precaution stuff. Nice try, builds fine, runs fine, freezes on ethernet packages.

Option 2: i took just the SAM7_EMAC_ISR.c from the lwip/rowley demo and kept the SAM7_EMAC.c from the uip/iar demo. a couple smaller adjustments, and i had to add vClearEMACTxBuffer from the lwip/rowley demo. i did that at the end of SAM7_EMAC.c same thing: builds fine, runs fine, freezes on ethernet packages

Option 3: stop using the EMAC code from the uip/iar demo and copy the whole EMAC directory from the lwip/rowley demo. I had to throw out anything lwip-specific and to replace it with the uip specific stuff (buffers and buffer sizes/nums as seen in the uip/iar code.). also i added the function lEMACSend and ulEMACPoll from the uip/iar demo emac code. The former had different prototypes between versions, the latter didn’t exist in the lwip/rowley code but is needed by uIP_Task.c. Nice try, but same problem as with options 1 and 2.

Anyways to sum up on the status (same for all 3 options): everything builds fine, but there’s a freeze problem probably with the emac isr code (maybe because of the difference in the content switching precautions and wrappers between the uip/iar and lwip/rowley code.
my guess is that someone who knows the emac isr code might see the problem quite quickly.

would you by any chance be willing have a look at it?
it’s a neatly packed archive file, about 120kB as .tar.bz2 (which should also be readable under windows i believe, with any halfway recent winzip or so) or 200kB in legacy .zip format (maximum compression, ouch)
i built it with gnu make and arm-elf-gcc 4.0.3, but i guess any arm-elf-gcc or compiler based thereon should do, so winarm should probably work for those who run windows.
i can mail it to you if you want or tell me how else to send you the archive


nobody wrote on Monday, April 24, 2006:

Nice work! 

If you send me the files I should be able to get them compiling on Windoze and see if I can spot what the issue is.  I can also do a dif to catch all the case problems you highlight (I can only test on Win32, so its not uncommon for this to happen, I appreciate people pointing it out).

I presume when using the inline save/restore macros you defined the ISR function using the ‘naked’ attribute?


(email address on contacts page of FreeRTOS.org site (r _dot! barry __-at-__ freertos 000dot000 org), don’t use the sourceforge email address as the attachment will get removed)

rtel wrote on Monday, April 24, 2006:

Oops, deleted my cookies then forgot to log back in.  Anyway, the last post was from me as is obvious from the email address.

rainer32 wrote on Monday, April 24, 2006:

You wrote:
> I presume when using the inline save/restore macros you defined the ISR function using the ‘naked’ attribute?

ahm, no, i didn’t. maybe that’s it?
i just sent the archive.
have a look at it and tell me


rainer32 wrote on Monday, April 24, 2006:

ahm actually i don’t know if i did
not knowingly anyways. i didn’t add any such attribute and don’t remember seeing any, but if there was already one and it was somewhere i didn’t look, could be?
but you’ll see that

rtel wrote on Monday, April 24, 2006:

Ok, I can replicate the problem which is a good start.  I have to pop out for an hour now but will look again when I get back.

One problem, using option 1, I can see the file used in the makefile is /EMAC_uip_iar_modified/SAM7_EMAC_ISR_alt.c but the symbol vEMACISR does not seem to be locatable in the debugger, and I cannot set a break point in that file.  Are you doing something cunning here?  I need to be able to set a break point in the file.

Incidentally, I can see a couple of errs in the file.  More in a bit.


rainer32 wrote on Monday, April 24, 2006:

i didn’t try it with a debugger so far.
and no, i didn’t do anything cunning. here’s what i made SAM7_EMAC_ISR_alt.c:
the function vEMACISR is exactly that from Demo/uIP_Demo_IAR_ARM7/EMAC/SAM7_EMAC.c, except that i added a call to portENTER_SWITCHING_ISR because there is one in the lwip EMAC ISR code and i thought this might be necessary to take care about the context switching thing since i didn’t use the assembler wrapper from EMAClISR.s79 (but hey, maybe that reasoning of mine is completely flawed. i don’t even know what portENTER_SWITCHING_ISR does, i just thought i’d do as in the lwip demo.

the only thing i added to that function is the line
static xSemaphoreHandle xSemaphore = NULL;
i did so because the function needs it and the lwip demo does it exactly that way. However, as i pointed out in my first big post, declaring the same variable static in two different c source files might probably lead to having two effectively distinct variables. so if for any reason the variable had to be the same in both cases (which is quite possible, i have no idea, i just followed the lwip demo here), then this could  lead to a problem without even throwing a warning at compile time.

rainer32 wrote on Monday, April 24, 2006:

by the way, only option 1 uses that file. options 2 and 3 don’t, since they use the EMAC ISR from the lwip demo

rtel wrote on Monday, April 24, 2006:

I will have to return to this tomorrow.  For now here are some notes:

1) I think you need a debugger, otherwise there are an infinite number of possibilities.

2) As per the compiler warning, the #pragma data_alignment=8 from the IAR build needs changing to the __attribute__((aligned (8))) GCC syntax.

3) The function vEMACISR() needs to be declared using __attribute__((naked)) to prevent the compiler prologue/epilogue code being added.  The context save must be the first and the restore the last thing in the function.

4) In the same function, portEXIT_SWITCHING_ISR() must be the last statement - after the line that clears the interrupt:

void vEMACISR( void ) __attribute__((naked));

void vEMACISR( void )
    /* This ISR can cause a context switch, so the first statement must be a
    call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
    variable declarations. */

    /* Variable definitions can be made now. */

static volatile unsigned portLONG ulIntStatus, ulRxStatus;
static portBASE_TYPE xSwitchRequired = pdFALSE;

    ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;
    ulRxStatus = AT91C_BASE_EMAC->EMAC_RSR;

    if( ( ulIntStatus & AT91C_EMAC_RCOMP ) || ( ulRxStatus & AT91C_EMAC_REC ) )
        /* A frame has been received, signal the uIP task so it can process
        the Rx descriptors. */
        xSwitchRequired = xSemaphoreGiveFromISR( xSemaphore, pdFALSE );

    /* If a task was woken by either a character being received or a character
    being transmitted then we may need to switch to another task. */

    /* Clear the interrupt. */

    portEXIT_SWITCHING_ISR( xSwitchRequired );


I have found that the EMAC interrupt is being entered, but a data abort is generated after a few interrupts.  This could be the data alignment.

Maybe this will give you enough to look at for now.  Let me know how you get on.


rainer32 wrote on Monday, April 24, 2006:

- ok, ok, i got the debugger out. (i recently switched to openocd with ddd and had to readapt my gdb startup script a little)

- i applied the changes you mentioned and went in with the debugger, with a hbreak on vEMACISR.
but then i wasted a lot of time without finding anything meaningful. actually, when i wanted to step, it looked like it jumped back inside the “if” block, which of course is nonsense, and i don’t know exactly what that was, but i guess it was a little problem with openocd or my config thereof. i’ll try to get that fixed tomorrow.

anyway, if the data alignment is the problem, it must be something else than those two replaced pragmas, since it still freezes after correcting those


rtel wrote on Tuesday, April 25, 2006:

It will be this evening before I can take another look unfortunately.  The makefile you supplied has optimisation turned up to the max, which may explain why it was jumping around the source code a bit.


rainer32 wrote on Tuesday, April 25, 2006:

i’ll try again with different optimization settings, but i really doubt this is the problem. as a matter of fact, it looks more like a gdb bug:
- i set it to break at vEMACISR and then i just go along stepping. To eliminate any interrupt-overload or so, i even tried the same after unplugging the ethernet port of my board and told the debugger explicitely to jump to vEMACISR.
the first 3 lines or so go normally.
but then, in the if block, it gets really warped: it jumps back a line or two, then goes out of that block but again goes back (wtf?) interestingly, openocd reports pc values that look correct (i.e. going forward without jumping around) while gdb shows weird jumps.

now it gets even worse: i thought, there might be some problem between openocd and gdb, so i tried it with “target sim” (arm simulator) instead. jeez, a couple lines after stepping out of the if block, gdb SEGFAULTS on me! not the target program, but gdb itself!
I tried it with 3 toolchains and the gdb that comes with them: howebrew gcc-4.0.3-based and gcc-4.1.0-based (all linux), AND windows gnuarm gcc-4.0.2-based (with insight-gdb and sim target)
all 3 tries give the same gdb segfault!
i’m dumbfounded. i mean, even if there was  something seriously warped with the program or the build options, that shouldn’t be a reason for the debugger to segfault on me.

so now i’m a bit at a loss of what to try (i don’t have anything other than gdb-based stuff).
what debugger do you use? if it’s gdb-based, did you try doing that (break on vEMACISR and steps)?



rtel wrote on Tuesday, April 25, 2006:

Looking at option 1, in the EMAC ISR file, are you settinig up the xSemaphore variable?

rainer32 wrote on Tuesday, April 25, 2006:

i added no particular setup. i had to add the line declaring it because vEMACISR needs that var. so i looked how the lwip demo did it and did exactly the same. however, as i pointed out a couple times already, this might indeed be a source of problems (in the lwip demo too, btw), cause declaring it static inside SAM7_EMAC.c AND in SAM7_EMAC_ISR_alt.c (or SAM7_EMAC_ISR.c in the case of lwip) probably has the compiler effectively treating it as two separate vars, which might be a very bad thing if the two files use the var to exchange data (i don’t know). I did exactly as in the lwip demo. in the original iar uip demo, this problem doesn’t exist (since vEMACISR is inside the file SAM7_EMAC.c, which we can’t do with gcc since it’s arm code).
i guess you’d know better than me if that double definition (as static in two separate files) is a problem. if you determine that it is, be aware that it’s also the way it’s done in the lwip demo, so you may want to change it there too.

rtel wrote on Tuesday, April 25, 2006:


The IAR port sets the data alignment and structure packing in the project file settings.  The GCC port uses __attribute__ settings.

Do a search for “__attribute__” in the directory structure, you will find that the places where the attribute modifiers are required are still in the code, just commented out as place markers.  Simply uncomment, making sure the ;'s are in the correct places, and every thing works.

Your data abort was caused by the uip buffer not being aligned correctly.

In my test program I have reduced the number of tasks and increased the stack sizes just as a debug process or elimination.  The code should work without doing this but keep an eye on the stack sizes.

If you are viewing the served pages in FireFox you might want to set the table font to courier to get the columns to line up nicely.

Recap (using option 1):
+ Change the ISR as per my previous post.
+ Ensure the sempahore gets initialised.
+ Change the #pragmas to __attribute__ aligned.
+ Search for all the other __attribute__ settings that have been commented out and comment them back in.



rainer32 wrote on Tuesday, April 25, 2006:

actually, i found the same var in yet a third file: in uIP_Task.c, line 68
afaik, these variables have the same name xSemaphore in all 3 files, but WILL be treated as separate vars at different locations (even temporary in case of uIP_Task.c). So if there’s any chance that this xSemaphore was supposed to keep some data to be interchanged between these 3 files (uIP_Task.c, EMAC/SAM7_EMAC.c and SAM7_EMAC_ISR_alt.c) or 2 files  in the lwip demo (EMAC/SAM7_EMAC.c and SAM7_EMAC_ISR.c), it should definitely be declared differently, e.g. NOT static, but normal global in one file (i guess that would be SAM7_EMAC.c) and extern in the other one or two files. the ‘static’ keyword will limit the scope to the file afaik (and the in-function definition in uIP_Task.c also).

unless i get some input from you saying otherwise, i’ll just try doing that

rainer32 wrote on Tuesday, April 25, 2006:


rainer32 wrote on Tuesday, April 25, 2006:

actually, just to be sure i didn’t forget or mess up anything, could you please mail me an archive (ideally any of tar.bz2, tar.gz, zip, rar, arj, tar) with your uIP_Demo_GCC_SAM7X directory? (use reply to the mail in which i sent the archive to you)


rainer32 wrote on Tuesday, April 25, 2006:

You wrote:
> + Ensure the sempahore gets initialised.
initialized how (to what?)
as said, i initialized the var to NULL as per the lwip demo. To what should I initialize it?

nobody wrote on Wednesday, April 26, 2006:

It is indeed two separate variable when declared static.  The semaphore is setup in one file, then passed to the other file.