Sunday, April 18, 2010

Porting code...

...or how to waste lots of time.

Writing portable code is more than just sticking to strict ANSI-C. If you look at the sources of programs or libraries that compile on different platforms, you will find lots of ifdef statements that provide the portability. It is actually pretty difficult to write portable code.

Currently I am into ARM development and I try to target just one OS: mine, on one platform: mine. But I want to use different compilers. I try to write code as portable as possible, without adding compiler specific things, but that just isn’t possible, especially when you target an embedded platform.

Initially I developped some code for GCC. Then I decided that it would be nice if I could use the Keil uVision tools as well. Getting my GCC code to compile with the RealView compiler (used by the uVision tools) was not too difficult, but getting it to work, was.

The problems were caused by, as always, the interrupts. In my code a timer and a UART use interrupts. With the GCC tools both worked fine, with the Keil tools only the UART worked. Uh oh... long debug hours ahead...

I remembered that the GCC code had an interrupt wrapper in the startup code, so all I had to do was to replace the Keil startup code with the GCC startup code. Easier said than done, because it turned out that the Keil assembler did not like the GCC assembly code. This code was definitely not tool-portable (even though the origin of the code clearly was Keil.).

Right, forget about GCC’s special interrupt code, let’s do it the Keil way. I found a Keil timer example that worked on my platform and I copied the code across to my GCC code and … it did not work. I examined the assembler code generated by the compiler for both cases and noticed that the entry and exit code was not the same depending on if the code was integrated in my GCC code or in the Keil example. Yet it was the same C-code, verbatim, since I copied it across, remember?

Or was it?

After stripping down my GCC code (and many hours of hair tearing) I finally discovered that the GCC code had defined away the __irq keyword! Aaargh! So that’s why I didn’t get the right entry and exit code for my ISR!

OK, so I quickly fixed this and now everything would work, right? Wrong!

Obviously there was another problem. My code was now working a bit, but it hung in a delay function. This delay function waited for the timer to reach a certain value before continuing. After some debugging I found that the problem was not so much the delay function itself, but returning from it, it made the program crash. Hmm, that smelled like stack problems.

To make a long story short, the hanging was caused by a function call from within the timer ISR to update a 10 ms timer. After many more debugging I finally found the reason: it was the example code that I had copied! The example proudly mentioned that it handled nested interrupts and I thought that that was mighty fine. But as it turned out, the way the example handled nested interrupts it could not handle function calls from within an ISR... Once the nested interrupts disabled, my Keil code finally worked as my GCC code.

In the end I did not have to make a lot of changes to my original code to port it to a different compiler. It was enough to set the include paths right, define away a GCC __extension__ keyword, add a wint_t typedef, re-allow the __irq keyword and disable nested interrupts, but these last two took me many hours to figure out. At least I now finally understand why the GCC startup code has this special interrupt handling code...

Thursday, April 8, 2010

The InterSceptre is almost ready!

It has been a busy period the last few weeks and I did not have the time to update this blog. Although it is still a rather busy time, I decided to write something anyway because I started working on the prototype of the InterSceptre.

Click for a better view. Notice the valid data on the LCD.

I received the PCB and the parts last Tuesday and I assembled the board. Even though the board is not very complicated, there are a lot of things to test. The first tests are promising. The power supply is fine and the board runs from 3V3 or 5V. There are three different 5V entry points (2x USB & one external power supply) and switch over between these inputs works without resetting the Sceptre board (or the PC).

Also working is the I2C port with discrete level shifter. It is discrete because I tried to avoid SMD parts on this board and through-hole integrated level shifters are hard to find. To test it I use the Pocket Terminal which is part of Elektor project 080253 Running-in bench. This terminal is supposed to run from 5V, but the Sceptre runs from 3V3, so I2C communication is incompatible. The level shifter fixes this and the fact that I can write to the terminal and read its keys means that all is working fine.

The four multiplexed DAC outputs are working, which is cool. I can control them with the rotary encoder on the terminal.

Not tested yet are the RS232 & RS485/DMX512 ports, the MIDI interface, the JTAG port, the SPI port and the digital I/O. The SPI port is particularly interesting as the board has space for a WIZnet WIZ812MJ internet module (not mounted for the photo, it should go next to the power connector). The digital I/O is hanging from the I2C bus and some direct from the processor. This is also true for the ADC inputs, so I suppose they will work.

As you can see from the photo, the InterSceptre was designed to fit a standard box from Teko. I did this because this way you can use the Sceptre-InterSceptre combination as a nice stand-alone device. You could only mount the interfaces you need and away you go.