Friday, August 13, 2010

NXP MBED aint so bad after all

I have been anti lpc lately. Was discouraging among other things the http://mbed.org development board. The two things that probably set me off and put the thing in almost-permanent storage is that the web based compiler tools and likely on top of that a whole sandbox/rtos. Dont remember didnt try it. Worse than that is the blue leds, near instant migraine headache when those things turn on, even, esp, out of the corner of my eye.

Saw it sitting there all sad in the pile of rejects and decided to give it one more shot, the web side says linux maybe it didnt before. Well it aint so bad after all (well the leds are killing me still, but you absolutely do not need to use their sandbox or compiler).

The copy the bin file to a flash drive thing is interesting and cool, much easier than the armmite pro which is one of the few lpc boards I do like. The extra chips must manage the flash drive thing because I was worried the main LPC1768 did it but got to thinking that if a program written in the sandbox crashed the flash drive would not mount and you would be bricked, so they had to have managed it separately. And did.

I looked at their Hello World binary and confirmed there was no encryption magic or other such thing to force you to use their sandbox, and decided to go for it. If you go to mbed.org and get the schematic (it may take you a while surfing but it is there). You will find that P1.18, 20, 21, and 23 are connected to the four leds along the bottom edge. The fast I/O ports are not what I was expecting, they are 8 bit registers so you have to not assume a 32 bit register manages the whole port as I did. Once I got past that it was easy to make a night rider like led blinker program:


/*blinker1.s*/.cpu cortex-m3
.thumb

.word 0x10008000 /* stack top address */
.word _start /* 1 Reset */
.word hang /* 2 NMI */
.word hang /* 3 HardFault */
.word hang /* 4 MemManage */
.word hang /* 5 BusFault */
.word hang /* 6 UsageFault */
.word hang /* 7 RESERVED */
.word hang /* 8 RESERVED */
.word hang /* 9 RESERVED*/
.word hang /* 10 RESERVED */
.word hang /* 11 SVCall */
.word hang /* 12 Debug Monitor */
.word hang /* 13 RESERVED */
.word hang /* 14 PendSV */
.word hang /* 15 SysTick */
.word hang /* 16 External Interrupt(0) */
.word hang /* 17 External Interrupt(1) */
.word hang /* 18 External Interrupt(2) */
.word hang /* 19 ... */

hang: b .

.thumb_func
dowait:
ldr r7,=0x10000
dowaitloop:
sub r7,#1
bne dowaitloop
bx lr

.thumb_func
.globl _start
_start:
ldr r0,=0x2009C022
ldrb r1,[r0]
mov r2,#0xB4
orr r1,r2
strb r1,[r0]

ldr r0,=0x2009C03A
ldr r1,=0x2009C03E
ldr r2,=0x80
ldr r3,=0x20
ldr r4,=0x10
ldr r5,=0x04

mainloop:
strb r2,[r0]
strb r3,[r1]
strb r4,[r1]
strb r5,[r1]
bl dowait
strb r2,[r1]
strb r3,[r0]
strb r4,[r1]
strb r5,[r1]
bl dowait
strb r2,[r1]
strb r3,[r1]
strb r4,[r0]
strb r5,[r1]
bl dowait
strb r2,[r1]
strb r3,[r1]
strb r4,[r1]
strb r5,[r0]
bl dowait
strb r2,[r1]
strb r3,[r1]
strb r4,[r0]
strb r5,[r1]
bl dowait
strb r2,[r1]
strb r3,[r0]
strb r4,[r1]
strb r5,[r1]
bl dowait
b mainloop

.end



/* memmap */
MEMORY
{
rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x40000
ram(WAIL) : ORIGIN = 0x10000000, LENGTH = 64K
}

SECTIONS
{
.text : { *(.text*) } > rom
}




You may want to look at my stellaris blinker at lmistuff.blogspot.com to understand more about the cortex-m3 and thumb/thumb2 only mode. For starters the exception table is different than other ARM cores. Other arm cores the table contains executable arm instructions which are usually a relative branch or a load pc with something. The cortex-m3 does not execute ARM instructions, at all, it is thumb/thumb2 only. So the exception table starts with the value to pre-load the stack pointer with, the second entry is the address in memory for reset, and so on. So other than the stack pointer thing it is similar to an interrupt vector table on other non-ARM/traditional processors. From the datasheet and/or users manual for the LPC1768 wee see that there is sram up to 0x10007FFF so that is why the stack pointer entry is 0x10008000.

My makefile looks like this:


#ARMGNU=arm-thumb-elf
ARMGNU=arm-none-linux-gnueabi

all : blinker1.bin


blinker1.bin : blinker1.s memmap
$(ARMGNU)-as blinker1.s -o blinker1.o
$(ARMGNU)-ld -o blinker1.elf blinker1.o -T memmap
$(ARMGNU)-objdump -D blinker1.elf > blinker1.list
$(ARMGNU)-objcopy blinker1.elf blinker1.bin -O binary

clean:
rm *.bin
rm *.o
rm *.elf
rm *.list


I am using the codesourcery lite toolchain at the moment. As with most of my programs you dont need a C or gcc library so the linux tool is not doing any linuxy stuff it is just a compiler I had laying around. Actually in this case it is an all assembler program so it is only binutils that is required and if you look at my other posts it is fairly simple to build binutils as a cross compiler(/assembler).

Plug the mbed in, it will mount as a flash drive, copy blinker1.bin to the root of that drive, perhaps remove other .bin files that are there (not sure how that works yet, is it alphabetical?), and press the button in the middle of the board. And your leds will blink in a pattern.

Wednesday, February 24, 2010

ARMMITE loading from linux

http://dwelch.s3.amazonaws.com/proglpc20100224a.tar.gz

http://dwelch.s3.amazonaws.com/proglpc20100225a.tar.gz

http://dwelch.s3.amazonaws.com/proglpc20101205a.tar.gz

I dont know why I though that the bootloader protocol, which I now know as ISP (In-System Programming) was a corporate secret and the one or two open source tools had some magic to them. Turns out it is well documented, well, maybe not WELL documented, but pretty good. As good as anything else in an LPC users manual (better than most).

So I have one of the Coridium ARMMITE pro boards that I bought from Sparkfun along with one of their usb to serial widgets that plugs in to power the board and provide serial access.

The code is ugly by many folks standards right now but I will work on it over time. But it does function on linux, is not tied to any libraries other than the basic serial access (termios?) that has been there for a decade as my serial port code is that old. command line, compiles easily with gcc. I have also included a couple of blink the led programs, one very simple and one very simple plus a few extra lines of code to speed the processor up to 60MHz from 20MHz.

The ARMMITE pro comes with some Code Read Protected (CRP) code for interpreting basic. Short the load C programming pins, and I had to then (after the power was on) press the reset button to get it into ISP mode. The only way around the CRP problem is to erase all of the flash blocks on one shot. Referring to the manual the Sector numbers table shows sectors 0 to 7. To erase the shipped with software (nope, its gone, cant recover, if you want to use this board as a basic interpreter stop reading this blog now) you need to use the P 0 7 then the E 0 7 command. Then you can write and read ram and flash and whatever.

2010-02-25 proglpc now reads a .bin file and programs it to flash.
short the loadc pins
power on
press the reset button
proglpc filename.bin
release loadc pins
press reset to see your program run

Ahh, this doesnt quite work, not sure how it did before, dtr needs to be down for this to program

change ser.c to add the drop dtr


unsigned char ser_open ( void )
{
struct termios options;
int status;

ser_hand=open("/dev/ttyUSB1",O_RDWR|O_NOCTTY|O_NDELAY);
if(ser_hand==-1)
{
fprintf(stderr,"open: error - %s\n",strerror(errno));
return(1);
}
fcntl(ser_hand,F_SETFL,FNDELAY);
bzero(&options,sizeof(options));
options.c_cflag=B19200|CS8|CLOCAL|CREAD;
options.c_iflag=IGNPAR;
tcflush(ser_hand,TCIFLUSH);
tcsetattr(ser_hand,TCSANOW,&options);
ser_maincnt=ser_buffcnt=0;

ioctl(ser_hand, TIOCMGET, &status);
status &= ~TIOCM_DTR;
ioctl(ser_hand, TIOCMSET, &status);

return(0);
}


20101205a version has the DTR fixed. Added blinker3 example which uses a 32 bit timer to blink the led instead of just a timed loop. Also blinker3 configures and sends bytes out the uart.

Tuesday, September 2, 2008

lpc 2148 blinker 1

Blinking the led on the LPC-H2148 board is actually pretty simple. With this example you will only need to build binutils (dont need gcc).

If you are afraid to write to flash (why?) you can compile this for sram only and load and start it from jtag.

To build for flash, use this linker script and these commands:


arm-thumb-elf-as vectors.s -o vectors.o
arm-thumb-elf-ld vectors.o flashmap -o blink.elf
arm-thumb-elf-objdump -D blink.elf > blink.list


To load using JTAG, power cycle the board, press reset a time or few, then:

openocd -f filename.cfg

In another console:

telnet localhost 4444
reset halt
flash write_image erase blink.elf
reset


If done right then when you power on the board it will start running this program.


/* flashmap */
MEMORY
{
rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x1000
ram(WAIL) : ORIGIN = 0x40000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
}


To build for sram only, use this linker script and these commands:


arm-thumb-elf-as vectors.s -o vectors.o
arm-thumb-elf-ld vectors.o srammap -o blink.elf
arm-thumb-elf-objdump -D blink.elf > blink.list


To load using JTAG, power cycle the board, press reset a time or few, then:

openocd -f filename.cfg

In another console:

telnet localhost 4444
reset halt
load_image blink.elf
soft_reset_halt
resume 0x40000000


Your program will be lost if you power cycle the board.


/* srammap */
MEMORY
{
rom(RXWAIL) : ORIGIN = 0x40000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
}


The program itself. Not much to it. Enable pin P1.24 as an output pin. Clearing the pin (setting the output low, ground) will ground the led and turn it on. Setting the pin high will turn off the led. A simple count down from N timing loop is used to delay the state change. Flash does not power up at full speed, and this program does not make any changes to the clock or flash speed.


/* blink.s */

.TEXT

.ALIGN
.CODE 32

b _start /* reset vector */
b .
b .
b .
b .
nop
b . /* IRQ */
b . /* FIQ */

.GLOBAL _start
_start:
ldr r0,=0xE0028018 /* LPC_2148_IO1DIR */
mov r1,#0x01000000 /* P1.24 */
ldr r2,[r0]
orr r2,r2,r1
str r2,[r0]

ldr r0,=0xE002801C /* LPC_2148_IO1CLR */
ldr r1,=0xE0028014 /* LPC_2148_IO1SET */
mov r2,#0x01000000 /* P1.24 */

mainloop:
str r2,[r0]
mov r3,#0x20000
delay1:
subs r3,r3,#1
bne delay1
str r2,[r1]
mov r3,#0x20000
delay2:
subs r3,r3,#1
bne delay2
b mainloop

.END

Openocd and JTAG

Finally got jtag working for the LPC-H2148, the config file with the openocd sources didnt quite work. The config below works with the Olimex parallel port wiggler and the usb ocd tiny, using the current openocd source (svn) built against the current libftdi, but NOT libft2xx. (dont need either of course for the parallel port). Uncomment the relevant section depending on the interface.

Changing the 14765 to 12000 (starting from the openocd config file) and adding the calc_checksum helped greatly. I dont know what the board/chip is doing but it helps greatly (if you cant connect) to power cycle the board, press the reset button a time or two, and run openocd (openocd -f filename.cfg). Telnet into openocd telnet localhost 4444

If you compiled for flash then:

reset halt
flash write_image erase blink.elf
reset


If you compiled to run out of ram only:

reset halt
load_image blink.elf
resume 0x40000000




#daemon configuration
telnet_port 4444
gdb_port 3333

#Parallel Port Interface
#interface parport
#parport_port 0
#parport_cable wiggler
#jtag_speed 0

# OpenOCD JTAG TINY
#interface ft2232
#ft2232_device_desc "Olimex OpenOCD JTAG TINY"
#ft2232_layout "olimex-jtag"
#ft2232_vid_pid 0x15BA 0x0004
#jtag_speed 20

#delays on reset lines
jtag_nsrst_delay 200
jtag_ntrst_delay 200

# NOTE!!! LPCs need reset pulled while RTCK is low. 0 to activate
# JTAG, power-on reset is not enough, i.e. you need to perform a
# reset before being able to talk to the LPC2148, attach is not
# possible.

#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst srst_pulls_trst

#jtag scan chain
jtag_device 4 0x1 0xf 0xe

target arm7tdmi little 0 arm7tdmi-s_r4

working_area 0 0x40000000 0x4000 nobackup

#flash bank lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765
flash bank lpc2000 0x0 0x40000 0 0 0 lpc2000_v2 12000 calc_checksum

Roll your own gcc

gcc is not the best, but widely used, works on most platforms, and you are far more likely to find information or help on the net than any other compiler. So why not use it right?

A good place for a pre-built is code sourcery. But if you want to build your own, there is really not much to it.


This works for 4.2.x not 4.3.x, just use 4.2.x




#IF WINDOWS
Go to http://www.mingw.org, find and download

MinGW=5.1.3.exe
MSYS-1.0.11-2004.04.30-1.exe

Install both
Run the Msys shell/prompt to continue as if on a native Linux system.
#ENDIF

#IF LINUX
Make sure you have texinfo, bison, and flex installed, as well as gcc, make and other typical programs
On ubuntu this would be

sudo apt-get install build-essential bison flex texinfo

Note the makeinfo error I am trying to avoid here is part of the texinfo package
#ENDIF

Most of this section is simply a list of the commands to type.

#IF LINUX
You probably dont run as root all the time so you may need to use a directory other than /arm or
as root create /arm and chown to your username so that you can finish the build as the user.
It wants to run from the path used to create it so think about where you want it and who you want
to use it. If you do all of this as root and keep it in /arm (and make it readable by everyone) everyone
can use it.
#ENDIF

Download http://ftp.gnu.org/gnu/gcc/gcc-4.2.2/gcc-core-4.2.2.tar.bz2
Download http://ftp.gnu.org/gnu/binutils/binutils-2.18.tar.gz

ZZZ='--target=arm-thumb-elf --prefix=/arm'
mkdir /arm
cd /arm
tar xzvf /path/to/binutils-2.18.tar.gz
cd binutils-2.18
mkdir build
cd build
../configure $ZZZ

#IF WINDOWS AND SOMETIMES LINUX
edit the Makefile in this directory
Find and change the line from

MAKEINFO = /arm/binutils-2.18/missing makeinfo

to

MAKEINFO = /bin/makeinfo

#ENDIF

make all install

(this will take a while)

/arm/bin/arm-thumb-elf-as --version

GNU assembler (GNU Binutils) 2.18
...

Now binutils, the assembler, linker and other utilties is complete. If you only want to use assembly language this is all you need

To clean up the binutils build files

cd /arm
rm -rf binutils-2.18

On to gcc

cd /arm
tar xjvf /path/to/gcc-core-4.2.2.tar.bz2
cd gcc-4.2.2
mkdir build
cd build
../configure $ZZZ --disable-libssp
make all install

#IF WINDOWS
This will fail at some point with errors that look like

In file included from ../../gcc/libgcc2.c:35:
./tm.h:6:28: error: config/dbxelf.h: No such file or directory
...

It doesnt like the -I by itself in the xgcc command line
The culprit is in gcc/Makefile, a line that starts with

INCLUDES = -I. -I$(@D) -I$(srcdir) ...

Just get rid of that second include

INCLUDES = -I. -I$(srcdir) ...

Then start the build again

make all install

and it will complete this time
#ENDIF

/arm/arm-thumb-elf-gcc --version

arm-thumb-elf-gcc.exe (GCC) 4.2.2

To clean up the gcc build files

cd /arm
rm -rf gcc-4.2.2

#IF WINDOWS
You can exit msys and then copy the arm directory tree from
z:\msys\1.0\arm to z:\arm
(so that your binaries are in z:\arm\bin\)
z:\ is of course whatever directory you happen to be working with C:\ for example
#ENDIF

Welcome to lpcstuff

Welcome, I thought I would keep track of my Philips LPC2000 microcontroller development board experiments.

Currently I have a few boards from Olimex like the LPC-H2148, LPC-H2124, and LPC-H2129.