Building firmware with gcc

Thanks, all.
I have tried the GCC. It compiles and links fine,but the final hex file can not work.I just got a blank screen on my DSO. I am just learning about GCC,IAR and the startup code. Initially, I thought maybe the different binary file format made the issue. IAR4 uses UBROF that is IAR’s private format, yet IAR5 and GCC use ELF.
Now,I realise that is not the real reason.
The bootloader(just IAP) was compiled by IAR4.X constantly. I used IAR5.0 to compile Ben’s code,it passed. The lib can work, app can’t. Allow me to explain the
procedure when power on. Firstly, the bootloader will run. It will detect one GPIO to determine whether or not to upgrade. If not, it will jump to the lib part.
At the end of “main” function, it will jump to start address of the app part. Using IAR5,app can not work,it means the start address of the app part is wrong.GCC can not work,I think, they have different reasons.

Yes, the elf format is not important. The “real” binary content gets stripped out of the elf file into the bin (or dfu) file, which gets loaded on the Nano. So whether the intermediate format is elf or ubrof does not matter.

Exactly this issue should be fixed by the patch I suggested in viewtopic.php?p=4498#p4498. Basically the patch makes the LIB do the same when jumping to the APP, as the bootloader does when jumping to the LIB: It reads the startup entry (reset handler) from the interrupt vector instead of using a hardcoded address of the startup entry.

I have tested the patch on an emulator, so I know that it compiles correctly and does the right thing. However, I can not see if it works on gcc, so I will need some of you to please test it on IAR 4.0 and 5.0.

Hello Tormod,
last night I have finally been able to compile a working firmware on IAR5. Here are the elf files you asked for: I really hope they let you gain some insight into what is missing for getting the gcc port on par!

Antonio
BenF_IAR5_elf.zip (84.8 KB)

Hi Antonio, thanks for the elf files! I am not sure what to look for, and I have not discovered anything special yet, but I am sure they will be a useful reference.

I have done some great progress. Since the display was not coming up, and I have no JTAG or serial connection, I explored the possibilities of the 1-bit debug facility that is the function generator output :slight_smile: I hooked up a voltmeter to the output, and modified the code to not control the pin from a timer, but as a normal output pin I could toggle manually.

With this I could confirm that the LIB starts up fine, and if I disabled the USB_Init, it would go through the whole main() and jump to the APP. So why didn’t the LCD come up then? I studied the disassembly in LCD_Initial(), and here the elf file from Antonio gave me a nice opportunity to compare with the IAR-generated code. It turns of that some “cowboy” macros in HW_V1_Config.h gives quite different code in gcc versus IAR:

#define LCD_nWR_ACT()   GPIOD_BSRR = GPIOD_BRR  = GPIO_Pin_5

The intention here (which happens to work in IAR) is that GPIO_Pin_5 (which is just one bit) should be written to GPIOD_BRR first, then be written to GPIOD_BSRR, in order to create a 1-0-1 pulse. Although these variables are volatile (and directly mapped to the peripherals registers) it is easy to imagine that the compilers might do things slightly differently. And effectively, changing this and similar constructs to:

#define LCD_nWR_ACT()   GPIOD_BRR  = GPIO_Pin_5 ; GPIOD_BSRR = GPIO_Pin_5

made the LCD came up!

Now if we have hundreds more of these small things to fix, this is going to be fun :slight_smile:

EDIT: I pushed the fixes to my gcc branch, but you will have to disable USB_Init yourself, since the gcc branch should stay in working state for IAR as well.

Congrads Tormod, clever idea! And great news, too: you are getting very close.

To make USB_Init work I guess you need to apply to the APP and LIB ASM_Function.s the same kind of massaging I’ve done with IAR’s linker directives - see the the changes on the svn here.

I have not tried on gcc yet, but instructing the linker to place code at a fixed address does not seem to be much harder than it has been with IAR, judging by this thread: How to locate variable at fixed address?

You should be able to quickly poke at the linker config files, and then modify your iar2gas script in order to translate the relevant instructions from IAR jargon to gcc parlance.

Antonio

I think I have pretty much taken care of this by linking ASM_Functions.o first, so the branch tables always ends up at the start of the .text section and have stable addresses. For now, I have given up iar2gas and tweak the gcc assembly files by hand.

Instead of adding any addresses to the linker script, I think BenF’s suggestion in the other thread about storing the branch table address inside the LIB vector table would make sense.

BTW, the patch I have applied for jumping from LIB to APP gitorious.org/dsonano/dso-firmwa … 0458df6904 should work fine with both IAR 4 and 5 as well. It gets rid of the need to know where __APP_start is located.

\o/ at last it works! The code now builds with gcc and even runs !

I was migrating some of the assembly stuff to C (like we should try to do anyway) and then it started to work. I am not sure exactly what went wrong before. I can imagine it has to do with wrongly set up function calls forcing a switch from thumb mode to arm mode, which is not allowed on cortex-m3 and will simply lock up with a hard fault. If a jump address does not have the LSB set, this will happen. So probably there was one single bit wrong in the old code :slight_smile:

Congratulations to your great work tormod! (and everyone else who helped on this)

Does it really run perfectly on the first try or is there a lots of smaller bugs? Do you notice any compiler improvements like faster code or bootup? I hope open source is better but on the other hand IAR is highly specialized and been in the game for a long time too.

AFAICS, it works perfectly. I have not tested for instance SD cards though. But I think it is pretty much everything works or nothing works in this game. For compiler improvements I think there is no appreciable difference. The gcc bin files are larger than the IAR bin files, but OTOH there is no code size limitation with gcc. If you want faster boot, just comment out the Delayms(2000) in the splash screen :slight_smile: The most important is that anyone now can now build (and install) the firmware with free software tools, on any platform.

Cool!

No I don’t want faster bootup, I was just curious if the code was more speed optimized with GCC but I don’t think so :frowning: Of course the coolest thing is the code size limitation is gone and we can depend only on OSS to build the firmware :slight_smile: What is the limit now, 128k?

Tried your gcc port - works as sweet as it could be :slight_smile: Thanks so much, Tormod!

I don’t know if it can be replicated on IAR: I fear the initialization code put in by the compiler cannot be linked after your own. Moreover, being explicit in your linker files means also conveying more information to future coders - hopefully, somebody else is going to take on!

That’s a really smart way for getting rid of one of the dependencies between APP and LIB: thanks to BenF for suggesting it, and to your for implementing it.

I’ll try it on IAR5 ASAP, and if it works (can’t see any reason why it shouldn’t) I’ll push it in the svn in place of my own code - your idea looks a lot cleaner than mine.

My next wish: it would be really nice if we could try to minimize the remaining differences among IAR4, IAR5 and gcc, in order to get a smaller code tree.

Thanks a bunch for your work,

Antonio

Yes, relying on the linker to put things in order is probably not very portable, and was also not meant as a final solution. Just commented on it to explain this was at least temporary taken care of and was not blocking things from working. You can probably tweak the linker script to have a branch table code section before the normal code section. Also, maybe you can disable the IAR built-in initialization code? For gcc, I have it explicitly coded in an assembly file, but I will migrate it to C eventually, and then it can be shared. Anyway, the better solution is what BenF suggested.

Um, I have not implemented it… But please go ahead :slight_smile:

Absolutely, that is my goal as well. My gcc branch should in principle work with IAR 4.0 and 5.0 as well (branch table addresses will still need manually tweaking of course), so it will be down to one tree at least. But I hope we can get rid of more of the compiler-specific files as well. Migrating things from assembler to C will help.

did a pull two makes and it loaded without a hitch.

Minor suggestion, it would be nice if the output of both builds went to a common place so uploading was easier.

Just found some other cheap JTAG adapters (not tested by me) which should work fine with openocd:

Thanks tormod and everyone else who helped on this. I have put the project to code.google.com/p/dsonano/source … #svn/trunk. If anyone want to commit his modification, you can tell me,I will add your ID to the commit members.

UPDATE: It works. The build instructions are maintained on the DSO wiki: http://garden.seeedstudio.com/index.php?title=DSO_Nano (in the Developer’s corner).



Status: Compiling and linking works fine. However, nothing works when I try to run it :frowning: Anyway, for those who want to work on this and hopefully fix it, here are the steps to build APP and LIB. First of all make sure you have your ARM toolchain in your path. Then get the code and build the APP:
</s>git clone git://gitorious.org/dsonano/dso-firmware.git dso-firmware cd dso-firmware git fetch origin gcc # only needed on older git versions git checkout gcc cd DS0201_APP/project/gcc make<e>
Now comes a manual workaround until we have fixed the lib->app jump. First find the reset vector (start address) of the APP:
</s>hd dso-app.bin | head -1<e>
This list the start of the vector table, we are looking for the reset vector in bytes 5-8, written backwards, in my case:

00000000 00 50 00 20 91 18 01 08 d1 18 01 08 d1 18 01 08 |.P. …|

From the above, this would be 08011891. Now enter this address as APP_START (instead of 0800C121) in the LIB:
</s>cd ../../../DS0201_LIB/project/gcc vi ../../source/ASM_Function.s<e>
So it will look like this in my case:
</s>__APP_Start ;void __APP_Start(void) B 0x08011891<e>
Then compile the LIB:
</s>make<e>
Use the ST DFU File Manager / Demo program or the DfuSe-enhanced dfu-util to flash the LIB and APP binaries to your DSO.



To update your tree from the git repository at a later point, just run:
</s>git pull<e>