Archive

Archive for the ‘ARM’ Category

Freaky Assembly?

March 9, 2008 Pari 1 comment

After a looong time, I was debugging some embedded C code and thought I found something freaky:

C code

for (i = 0; i < 1000000; i++);

ARM code disassembly (as generated by GNU ARM gcc)

0×0000019c <main+196>: mov r3, #0 ; 0×0
0×000001a0 <main+200>: str r3, [r11, #-16]
0×000001a4 <main+204>: b 0×1b4 <main+220>
0×000001a8 <main+208>: ldr r3, [r11, #-16]
0×000001ac <main+212>: add r3, r3, #1 ; 0×1
0×000001b0 <main+216>: str r3, [r11, #-16]
0×000001b4 <main+220>: ldr r2, [r11, #-16]
0×000001b8 <main+224>: mov r3, #999424 ; 0xf4000
0×000001bc <main+228>: add r3, r3, #572 ; 0×23c
0×000001c0 <main+232>: add r3, r3, #3 ; 0×3

0×000001c4 <main+236>: cmp r2, r3
0×000001c8 <main+240>: bls 0×1a8 <main+208>

The three highlighted lines above in affect initialize r3 with 999999 (first initializes r3 with 999424, then adds 572 to it, then adds 3 to it).

What puzzled me was why couldn’t it do that directly (mov r3, #999999)?

Then after some scratching my head, an almost faint memory of ARM assembly language dawned on me… ARM instructions are 32-bit, of which Operand 2 can be only 12-bits. In addition:

- Of these 12 bits, 8-bits are for data, and 4-bits are used for ROR.
- The ROR bits are in turn multiplied by 2 before being applied on the 8-bits.

The combination of ROR and shifting by 2 greatly extends the range. The assembler automatically does it for you if it sees an operand greater than 8-bits.

This can be a great interview question :-).

Do the math, verify…

999424 + 572 + 3 is the closest tuples you can get to add up to 999999 using the 12-bit ROR with x2 multiplier for the RoR.

Just for verification, here are the instructions from memory:

1b8: 3D39A0E3 ; 0xE3A0393D
1bc: 8F3F83E2 ; 0xE2833F8F
1c0: 033083E2 ; 0xE2833003

To get 999424 (0×0F4000):
0×0000003D ROR 18 (0×9 x 2) = 0×000F4000 (ROR 18 = LSL 6)
As confirmed by the instruction: E3A03 93D

To get 572 (0×023C):
0×0000008F ROR 30 (0xF x 2) = 0×0000023C (ROR 30 = LSL 2)
As confirmed by the instruction: E2833 F8F

To get 3 (0×0003):
0×00000003 ROR 00 (0×0 x 2) = 0×00000003 (ROR 00 = LSL 0)
As confirmed by the instruction: E2833 003

Note: the LSL is just for convenience, it’s good only if data has all zeros padded on the left (at least enough to cover the LSL).

Categories: ARM, Coding

ARM Toolchain – Crosstool

November 28, 2007 Pari Leave a comment

Was able to get an arm-elf toolchain built and working fine, but not so much luck in building an arm-elf-linux toolchain. It cross-compiled programs without errors, but the compiled executable crapped out at runtime. So googling for answers… I came across Dan Kegel’s crosstool – a really cool GNU toolchain builder. It downloads all the correct gcc, glibc, binutils, etc. and builds your toolchain. I built two toolchains, arm-unknown-linux and arm-xscale-linux. The toolchain built with it works great.

Note:
The Ubuntu shell is not bash by default! Instead it is linked to something called dash. Just make sure you relink /bin/sh to bash instead of dash. No idea when they did this, but I found that out after encountering this maddening error, pointing to some header files during the build:

missing terminating ” character.

Using it:

Example (for kernel compilation makefile):

export ARM_TOOLCHAIN=/opt2/crosstool/arm-unknown-linux-gnu/bin
export PATH=$ARM_TOOLCHAIN:$PATH

make ARCH=arm CROSS_COMPILE=arm-unknown-linux-gnu-

Categories: ARM, Linux

ARM Toolchain

November 22, 2007 Pari 1 comment

Updated (April 26, 2008)

Here’s how I built a 64-bit GNU ARM toolchain (cross-compiler x64 to ARM). So far this has been working well for me on an LPC2148 (ARM7TDMI-S), i.e. gcc and gdb via OpenOCD JTAG.

Notes:

  1. Some builds (like binutils-2.18 and newlib-1.15) needed the setting MAKEINFO=/usr/bin/makeinfo to be passed to the make (binutils-2.17 and newlib-1.16 didn’t need this).
  2. Update: some systems (like Ubuntu 8.10) have strict checking turned on, where warnings are treated as errors. You may need to disable this the build of binutils and gdb using the –disable-werror configuration option.

Here are the steps:

environment (needed only for build):

export BINUTILS_VERSION=2.18
export GCC_VERSION=4.2.3
export NEWLIB_VERSION=1.16.0
export GDB_VERSION=6.8
.
export DIST=/opt1/gnuarm.dist    # tars will be downloaded here
export WORKDIR=/opt4/gnuarm.tmp    # tars will be unzipped and built here
export GNUARM_HOME=/opt/gnuarm   # Resulting binaries will be installed here
.
export SRC=$WORKDIR/src
export BUILD=$WORKDIR/build
export PREFIX=$GNUARM_HOME
export TARGET=arm-elf
.
md -p $DIST
md -p $SRC
md -p $BUILD
.
sudo mkdir -p $PREFIX

download:

cd $DIST
wget ftp://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VERSION}.tar.bz2
wget ftp://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.bz2
wget ftp://ftp.gnu.org/gnu/gdb/gdb-${GDB_VERSION}.tar.bz2
wget ftp://sources.redhat.com/pub/newlib/newlib-${NEWLIB_VERSION}.tar.gz
wget http://www.gnuarm.com/t-arm-elf

untar:

cd $SRC
tar jxf $DIST/binutils-${BINUTILS_VERSION}.tar.bz2
tar jxf $DIST/gcc-${GCC_VERSION}.tar.bz2
tar jxf $DIST/gdb-${GDB_VERSION}.tar.bz2
tar zxf $DIST/newlib-${NEWLIB_VERSION}.tar.gz
cp $DIST/t-arm-elf gcc-${GCC_VERSION}/gcc/config/arm/t-arm-elf

binutils:

md $BUILD/binutils
cd $BUILD/binutils
$SRC/binutils-${BINUTILS_VERSION}/configure –target=$TARGET –prefix=$PREFIX –enable-interwork –enable-multilib
make all install 2>&1 | tee make.out

gcc core:

md $BUILD/gcc
cd $BUILD/gcc
$SRC/gcc-${GCC_VERSION}/configure –target=$TARGET –prefix=$PREFIX
–enable-interwork –enable-multilib –enable-languages=”c,c++” –with-newlib –with-headers=$SRC/newlib-${NEWLIB_VERSION}/newlib/libc/include

make all-gcc install-gcc 2>&1 | tee make.out

newlib:

md $BUILD/newlib
cd $BUILD/newlib
$SRC/newlib-${NEWLIB_VERSION}/configure –target=arm-elf –prefix=$PREFIX –enable-interwork –enable-multilib

make all install 2>&1 | tee make.out

gcc (phase two):

cd $BUILD/gcc
make all install 2>&1 | tee make.out

gdb:

md $BUILD/gdb
cd $BUILD/gdb
$SRC/gdb-${GDB_VERSION}/configure –target=$TARGET –prefix=$PREFIX –enable-interwork –enable-multilib

make all install 2>&1 | tee make.out

post-setup:

echo ‘export GNUARM_HOME=/opt/gnuarm’ >> ~/.profile
echo ‘export PATH=$GNUARM_HOME/bin:$PATH’ >> ~/.profile

The scripts can be downloaded from here.

Categories: ARM, Linux

ARM boards

September 8, 2007 Pari Leave a comment

Just got back from a trip to Chicago – Oak Park, a pretty nice area, a nicely renovated “gentrified” neighborhood, west of Chicago.

Researching a good ARM board to buy. Narrowed it down to these (all these boards have USB and SD card reader):

ARM7TDMI-S boards:

  • Olimex SAM7-P256 (SAM7-Pxxx Rev. E) – Atmel AT91SAM7S256, 256K Flash, 64K RAM, 60MHz, 18MHz crystal. $87.
  • Olimex LPC-P2148 – NXP LPC2148, 512K Flash, 32K+8K RAM, 60MHz, 12MHz crystal. $77.

.
ARM7TDMI-S boards w/Ethernet:

  • Olimex SAM7-LA2 – Atmel AT91SAM7A2, 1MB Flash, 4MB SRAM, 30MHz, 6MHz crystal. $140.
  • Olimex SAM7-EX256 – Atmel AT91SAM7X256, 256K Flash, 64K RAM, 55MHz, 18MHz crystal. This board is loaded with stuff. $120.

.
ARM920T boards w/MMU (for running embedded Linux):

  • Olimex CS-E9302 – Cirrus Logic EP9302, 16MB Flash, 32MB SDRAM, 200MHz. Cirrus Logic has a very good linux forum. $180.
  • Olimex SAM9-L9260 – Atmel AT91SAM9260, 512MB NAND Flash, 64MB SDRAM, 180MHz, 18MHz crystal. $217.
  • … or just get a Slug – XScale IXP420 (ARMv5TE), 8MB Flash, 32MB SDRAM, 266MHz. $80.
Categories: ARM

Which RTOS?

August 14, 2007 Pari Leave a comment

After scouring through tons of MCU’s I’ve decided to go with the Atmel AVR, in particular the ATmega168.

But then, my recent adventure into the Slug’s hardware, got me thinking ARM. After much researching, I settled for Atmel’s AT91SAM7 series of ARM MCU’s.

My next thought was how I can run Debian/ARM on it. But unfortunately that was quickly ruled out – as the largest of the 7S or 7X series has only 512K Flash and 128K SRAM. Note that the 7SE series has an external memory bus.

So what can I squeeze into 256K Flash and 64K RAM? My hunt came up with these top 3 (in terms of the number of microcontrollers each has been ported to):

  1. FreeRTOS (्free)
  2. uC/OS-II (commercial)
  3. eCos (pdf book: Embedded Software Development with eCos)
  4. TNKernel (free)

And these bootloaders:

  1. u-Boot
  2. Redboot
  3. Apex

Categories: ARM

Choosing a Microcontroller

August 12, 2007 Pari Leave a comment
Categories: ARM

Embedded Systems

July 30, 2007 Pari Leave a comment

Like many who got onto the IT bandwagon, I never got to utilize what I was trained in – electrical engineering. After a career of high-level application development (i.e. in the IT Industry), I’ve taken the plunge, into the embedded world – back to my roots.

It really is an exciting and much more challenging area to be in – compared with drudgery of enterprise software development (fatware – where you don’t care about efficiency, you just slap on more memory, disk, cpu’s). Code-for-code embedded systems development pays a lot more too :-). I guess because Java programmers are a dime a dozen, but embedded systems need a tighter subject matter expertise. Compared with enterprise software development, one thing that sets embedded systems apart is the meticulous attention given to code correctness, efficiency, and reliability.

I have to thank the Slug for getting me into the world of embedded. It got me into learning about embedded Linux systems, embedded hardware, ARM processors, and 8-bit microcontrollers.

Surprisingly very little has changed since the Zilog Z80 (years ago) in terms of how they work. What has changed is that the CPU and all its peripheral components (RAM, EEPROM, Flash, USART, ADC, DAC, clock circuitry) have been all compressed into a single unit – the microcontroller (uC or MCU). And the cost typically around $2 and consumes typically less than 1W (compare that with $200 and 40W of CPU of PCs – I know it’s an unfair comparison, but how often big wig consultants propose CPU driven solutions to do an MCU’s job).

Categories: ARM

ARM Processors

July 29, 2007 Pari Leave a comment

What is an ARM processor? For those of us who have been living in the dark ages (that’s me!)… it stands for Advanced RISC Machine.

What is RISC? In short, once upon a time microprocessor engineers (in particular at Intel) thought it was a great idea to have the CPU handle more and more complex instructions. However, as the complexity increased, CPU’s were becoming power-hungry beasts with big fat instructions trying to accommodate just about everything (yes, you can even throw in the kitchen sink in there also). The downside of it is that it gave C compilers very little room for optimization – found it hard to churn out optimized code. In contrast RISC assembly language instructions are simple (the way microprocessor assembly languages started out to be), and easily optimized. See RISC vs CISC.

Not only is the C language far from dead, it is a very important language. Everything is written in C – all your operating systems, high-level languages, etc. As for embedded systems go, C – is where the metal meets the road, the software meets the hardware. Most of what you can do in assembly language, you can do in C. One can view C as a portable high level assembly language (in fact back then that was the reason that prompted it’s creation).

ARM processors (ARM9 and above) can be pretty overwhelming at first (compared with 8-bit microcontrollers). ARM based embedded systems are growing at a phenomenal rate – so it is worth getting to know if you’re getting into embedded systems.

Categories: ARM