Low level embedded example programs for the pic32 (UBW32 and CUI32 boards)
C Assembly
Switch branches/tags
Nothing to show
Latest commit 4c3485d Mar 14, 2012 @dwelch67 updating readme


You may see that I have a lot of other ARM based projects at github,
I do have a lot of low level ARM experience, as well as a fair amount
with other platforms but never got into MIPS.  Have wanted to but
needed a starting place.

So this year I bought a couple of boards from Sparkfun.  The UBW32


I bought is now retired and replaced with a newer one.  I dont know if
that is good or bad as I found PIC32MX4 tools after buying this CUI32


Specifically this tool:


Linked to from this page:


Not without problems of course.  libhid-dev is apparently not supported
by Ubuntu, or at least 10.10.  10.04 does have it and I was able to
get the sources from debian/ubuntu for 10.04 and build and install
it on 10.10.  Have not tried the newer Ubuntu versions....

Building the Microchip pic32 compiler from sources was a bust, more
work than I was interested in when the current llvm and stock gcc
are so easy to come by.  I am not interested in canned libraries, and
$900 is way out of the hobby budget for such tools.

I did find that the Microchip c32 compiler is available in pre-built
32 and 64 bit Linux versions.  You have to pay to get -O2 to work.

Codesourcery is now completely Mentor Graphics, so we will see what
happens with that .  Hopefully they wont make the typical mistakes that
cause the product line and purchase of the company to be a bust for
the existing user base.

So I still have a lot to learn about MIPS and the instruction set, I
was able to get enough assembler going to boot and run some sample

These are NOT StickOS nor UBW32 programs.  These are C and/or assembly
programs that replace StickOS or UBW32.  You can always put that
firmware back on the board, so long as you dont mess up the lower
area of flash.  The xD000000 - xD005000 range of flash at a minimum
is preserved for the bootloader, between xD005000 and xD006000 is
for exception vectors or something like that and the user programs
can/should start at 0xxD006000.  Mess up the flash below 0xxD005000
and maybe you brick the board, maybe not, you have been warned.

I assume it may be crt0.o from the Mirochip tools, who knows but
the UB32 firmware .hex file used the physical addresses in the
0x1D006000+ range, but the first few instructions switched to a
0x9D006000+ range (thus the 0xxD006000 nomenclature above), so I made
my linker script cause the same to occur, executes as if it was
0x9Dxxxxxx but build a .hex file for 0x1Dxxxxxx.  Using 0x80000000
for ram goes along with the 0x9Dxxx flash and it appears to work just
fine so far.

Microchip is using little endian so -EL is used on all the gnu command
lines.  This is critical if you leave that off and get big endian
.hex files, well it wont work...

The ubw32 flash loader program did not like a type 05 entries in the
.hex file, probably a simple change in that program, which is not mine,
so I wrote a quick program that takes the binutils created .hex file
and creates another .hex file with the offending line removed.  The
ihex tool takes something.hex in and creates something.hex.hex.  The
.hex.hex file is the one you want to feed the ubw32 loader.

Codesourcery which I think is completely switched over to Mentor
Graphics now, is currently THE place for ARM based gcc tools, so I went
there to get MIPS based tools.  And that is what was used for gcc and
binutils with these examples.

I normally build the current llvm release (2.9 at the moment) as well
as a copy of the cutting edge trunk from the svn repo.  They take a
while to build, if you have a multi core processor using make -j num
makes a huge difference.  Their make file system is not perfect
so unfortunately you have to make clean if there have been changes.

LLVM is great as a cross compiler, you get all the targets in one
tool, unlike others where you have to compile a new toolchain for each
target.  Other than 32 vs 64 bit ints you can do most of your work
target independent and then the last step go from bitcode to target
specific assembler.  I use binutils assembler and linker to merge it
with startup code and other hand written assembler and take it to a
final binary.  I had some relocation problems both with gcc and llvm
using -G0 on the gnu side and -relocation-model=static or
-relocation-model=dynamic-no-pic with LLVM (llc).  As of this writing
for the blinker02 example both static and dynamic-no-pic produced the
exact same output.

Examine the makefile for more on how to use llvm
for cross compiling, at least one way to do it.  I find it best to
build all the C code, then use llvm-link to link into a single
bitcode file.  Then optimize at that point where the optimizer has
the most amount of meat to crunch on.  Then turn it into a single .s
file to feed binutils.

As of this writing there are only a couple of examples, an assembly only
example using a counter based delay, blinker01.  Blinker02 is a baseline
C based example.  Future examples will use more peripherals and get
progressively more complicated.  No desire to clone the Microchip
libraries or anything like that, take the programmers reference,
schematics and figure things out.

In case you want to roll your own tools that you can compile these
examples with here are some notes.  Binutils is used by both gcc and
llvm in these examples, gives you an assembler and linker which
is all you need if assembly language is what you are after.  If you run
linux/Ubuntu you probably already have a number of the development tools
as you are probably already a programmer/developer.  Things like
build-essential, automake, etc. you will need bison and flex which
you may not already have, and for the more recent gcc versions
libgmp3-dev, libmpfr-dev and libmpc-dev (apt-get install all of these
items BTW).

So binutils, at the time of this writing the most current is:
wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.1a.tar.bz2

Note 2.22 fails to build for mips

> tar xjvf binutils-2.21.1a.tar.bz2
> cd binutils-2.21.1
> mkdir build
> cd build
> ../configure --target=mips-none-elf --prefix=/opt/mips-none-elf
this takes a bit, not long
> make
this takes longer depending on your machine, if you have multiple
cores then put the number of cores:
> make -j 4
this still takes a while but much faster in parallel.  you may figure
out on the way that you need to install something else and have to try
a few times.  using a directory (like build, it doesnt have to
be a subdir of the binutils sources) to configure/build in you can
easily just delete that directory instead of the whole binutils tree
to start over fresh.  when you get a clean build then
> make install
that might need a sudo on it...

Add this to your path so gas and ld are available for the gcc build.
> PATH=/opt/mips-none-elf/bin:$PATH

Now for gcc if you are interested
>wget http://ftp.gnu.org/gnu/gcc/gcc-4.6.1/gcc-core-4.6.1.tar.gz
>tar xzvf gcc-core-4.6.1.tar.gz
> cd gcc-4.6.1
> mkdir build
> cd build
>../configure --target=mips-none-elf --prefix=/opt/mips-none-elf \
>--disable-nls --enable-languages=c --disable-libssp --disable-libmudflap \
>--disable-libquadmath --without-headers --with-newlib
takes a while, not long
takes a really long time, multi core or fast computer makes a huge
difference, put the number of cores in there
>make -j 4
same deal, if you didnt get libmpfr or libmpc for example you will
have to keep trying.  not long ago a single apt-get install libmpfr-dev
would give you the things you needed for building gcc, then it was that
you had to do both libmpfr and libgmp3, now you have to manually do all
three libmpfr-dev, libgmp3-dev and libmpc-dev.  to get a gcc 4.6 built.
of course I am running an older Ubuntu 10.04 LTS. and 10.10 on some
machines.  when gcc finishes building successfully
>make install
I dont know if that needs a sudo or not, it might.

Now anytime you want to use it PATH=/opt/mips-none-elf/bin:$PATH
tools are mips-none-elf-gcc, mips-none-elf-as, etc.

When using with my Makefiles either:
> make MIPSGNU=mips-none-elf
Or change the line in the makefile to use the alternate prefix.  It is
possible the tools will build for you with the same prefix as
Codesourcery used.  mips-sde-elf.

Building the llvm 29 release

>svn co http://llvm.org/svn/llvm-project/llvm/branches/release_29/ llvm29
>cd llvm29
>cd tools
>svn co http://llvm.org/svn/llvm-project/cfe/branches/release_29/ clang
>cd ..
>./configure --enable-optimized --disable-doxygen --prefix=/llvm29
takes forever, -j num helps greatly. can change it from go get lunch
amount of time to go get a coke from the coke machine amount of time.
>make install

Building the trunk is as simple:

>svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
>cd llvm
>cd tools
>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
>cd ..
>./configure --enable-optimized --disable-doxygen --prefix=/llvm
>make install

For both from your toplevel llvm or llvm29 source directory

> make update

will pull in svn updates for both llvm trunk and clang trunk.  The
cutting edge development will have daily activity and there are definitely
times where some checkins do not work, sometimes you are doing a
update while pushes are going in, so I normally do two or three
make updates in a row to wait for no activity.  Definitely, unfortunately
do a make clean to clean out intermediate files, unfortunately the
make system doesnt catch everything, the make, make install again.
If it fails to build, try some more make updates or wait for a while
for whomever to find the build bug and fix it and check in a patch.

A/The reason for having the trunk is that when you find and want to file
a bug you may find that a number of them have been found and fixed and
by running the prior release, it is stable but does not have all
bugfixes backported, if any.

The above (gcc) does not necessarily give you a C library, or even gcc
library for that matter, I have no use for those in an embedded
environment so it doesnt bother me.  It might bother you, so more work
may be required. Likewise I dont use C++ so I use the core gcc tarball
not the full gcc tarball.  With gcc in general you are likely to have
floating point problems, with this chip not having an fpu (well I dont
see it mentioned in the docs) a soft fpu with gcc is that much more
painful.  Here again I have no use for floating point in embedded work
so these tools usually work great for me.

Apple has put a lot of resources into llvm development putting the results
back into the open source world.  The last couple bugs I filed were
handled by @apple.com email addresses during weekday work hours.  I think
llvm is used for iphone app development so the core compile and at least
arm backend is maturing nicely.