Sunday, July 30, 2006

Interrupt Counting

What should the interrupt routine do when I press the button? Well, to get this working and feel confident that it *is* working, it's a good idea to make the interrupt routine increment a counter and watch the counter variable in the debugger. That way one button press should be seen equal one counter increment. So my skeletal interrupt routine would be like:

unsigned long volatile counter = 0;

/* External Interrupt Function called when EXINT0 occurs */
void pressed (void) __irq {
counter++;
...
}

Saturday, July 29, 2006

Button Interrupts

I'm going to use the same button macro code I used in the polling example to take a pin 1 low representing the button press. I can connect that pin to external interrupt 0 using the following statement:

// Tell the Pin Function Select Register
// that EINT0 is on pin 1
PINSEL0 = PINSEL0 | (3 << 2);

If you put this code in the previous main before the while loop and then single step you can see Pin 1 in the Pin Connect Block being changed from GPIO Port 0.1 to EINT0.

Friday, July 28, 2006

Is VIC there?

Fueled by my new confidence in debugging interrupt routines I started hacking the timer interrupt example. The user manual for the LPC214x family seems to have everything I could possibly want to know about the VIC and how to connect interrupts to pins. However, finding all the relevant bits has been quite a challenge. I also had a look at this which gave me some additional clues but again wasn't exactly a cut-and-paste job.
I started out by writing a little main that just had a heartbeat waggling a pin. (That way I would know if the LPC had run off into the weeds as the result of broken interrupt code.)
BTW: The masters of my daytime universe tell me I can publish code snippets like the below without all the copyright stuff, hence the "..."; an exercise left to the reader. ;-)


...
int main (void) {
IODIR0 = 0x00000000; // GPIO Port 0 is input (default)
IODIR1 = 0x00000001; // GPIO P0.1 defined as Output
while (1) { // endless heartbeat loop
IOSET1 = 1;
wait();
IOCLR1 = 1;
wait();
}
...

Monday, July 24, 2006

We interrupt this program...

I have decided that polling a button to see if it's been pressed really is uncool. A much more realistic setup is to attach a button to an interrupt -- press the button and your program enters an interrupt service routine where you can service the button press. This is much more what embedded software is all about.

However, the one problem for me is that I really hate writing interrupt code. I have found setting up an interrupt controller and enabling interrupts one of the most hit and miss bits of writing embedded software. There's always something that I forget or that isn't clear in the manual. There I sit carefully single stepping my interrupt setup code right up to the "Enable Interrupts" statement. One more step and Kachow! the processor is off in the weeds without any real clue of how it got there. Repeat until out of coffee.

So I'm approaching writing code for the Vectored Interrupt Controller (VIC) on the LPC2148 somewhat with trepidation.

Looking in the examples in the RealView Microcontroller Development Kit, I see there is one example aptly named "interrupt" that sets up a couple of SWI's and a FIQ but sadly doesn't really setup the VIC. I'm sure I'll need more than a couple of interrupts for this project, so setting them up on the VIC seems to be the way to go.

Poking around the discussion forum I came across an article here that dealt with setting up an entry in the VIC vector table to handle a timer interrupt. I took this code and built it with the RealView Microcontroller Development Kit. I then loaded the code up in the simulator and single stepped it. To my delight, I found that I could see the internals of both Timer0 and the VIC being set up, since they are both simulated peripherals on the LPC2148. You can try this at home too by downloading the project here and single stepping it.

Friday, July 14, 2006

Pushing my button

It seems I can waggle the pins using the PORT0 variable in much the same way as I can waggle the GPIO under program control. Looking in the manual, the keyword "signal" hooks the function that succeeds it into the simulator so that it runs alongside the simulation. The manual says there's a bunch of stuff I can do with this to simulate signals coming in with specific intervals. The swatch and twatch functions can pause a running signal function for seconds or CPU states respectively.

So the signal function in the Traffic example sets pin P0.14 low, lets the simulation run on for a simulated 50 milliseconds and then takes P0.14 high.
A quick hack of this code and I get a button for my code:

PORT0 = 0x00000001; /* set P0:1 low: Key Input */
/* define a debug function for the push button */
signal void push_button (void) {
PORT0 &= ~0x00000001; /* set P0:1 low */
swatch (0.05); /* wait 50 msec */
PORT0 = 0x00000001; /* set P0:1 high */
}

/* define a toolbar button to call push_button */
define button "Push my button", "push_button ()"



You can try this example by downloading it here

Thursday, July 06, 2006

Pushing a button

The ability to waggle a pin low and high via a mouse click in the debugger and read its state in a program may seem somewhat unexciting, but it's a start for me. Looking at some of the other examples in the RealView Microcontroller Development Kit, I note that there are several that use buttons that appear in a window called the "Toolbox". A button that I can push to waggle the pin is exactly what I am looking for.

The Traffic example contains a button that allows me to simulate the "Push to walk" button at a crosswalk. Whenever I start the debugger and simulation for this example some commands and C-like code get loaded into the debugger at startup. These are shown scrolling past on the debugger's output window. But where do these commands come from? A quick grep of the Traffic example's directory for one of the strings that scrolled past and I find that the Traffic example has a .ini file that contains the debugger commands. Interesting...

Digging a little further, I find that the project options allow me to specify that a .ini file is executed when the debugger session commences. This is neat as it enables me to consistently set up my debug world with breakpoints, watchpoints, etc. whenever I start debugging. Moreover, it enables me to define buttons!

The .ini file for Traffic looks like this:

PORT0 = 0x4000; /* set P0.14 low: Key Input */

Hmmm... I think they mean high here!

/* define a debug function for
the pedestrian push button */

signal void push_key (void) {
PORT0 &= ~0x004000; /* set P0.14 low */
swatch (0.05); /* wait 50 msec */
PORT0 = 0x004000; /* set P0.14 high */
}

/* define a toolbar button to call push_key */
define button "Push for Walk", "push_key ()"
...

Tuesday, July 04, 2006

Blinky Hack

A quick hack of blinky and I now have the code below which polls pin 1 on Port 0 of the GPIO and if it goes low (by me clicking it) it sends pin 1 on Port 1 high.

The problem with this is my button simulation is more like a switch. I have to click the pin to turn it low and click again to turn it high. That isn't really what the LogStick "button" is all about. I need to find a more realistic button emulation. Hmmm...


/* Example program to detect a Pin
attached to GPIO going low which
represents button press */

...

#define PINMASK 0x00000001

/* IF masked pin number is low THEN button pressed */
#define BUTTON_PRESSED ((IOPIN0 & PINMASK)== 0)

void wait (void) {int d; for (d = 0; d < 1000000; d++);}


int main (void) {
/* GPIO Port 0 is input (default after reset anyway) */
IODIR0 = 0x00000000;

/* GPIO P0.1 defined as Output */
IODIR1 = 0x00000001;
while (1) {
/* IF button pressed, toggle an output pin*/
if (BUTTON_PRESSED) {
IOSET1 = 1;
wait();
IOCLR1 = 1;
}
}
...

Sunday, July 02, 2006

Pinning down the UI

I have had a quick look at the LPC2148 user manual in the Device Database here

In chapter 8, I found that the LPC2148 has 2x32 bit GPIO I/O ports which I can configure to drive or be driven by all manner of things on the chip, one bit of which I could use for the LogStick's button. It's possible to poll the pins to see if they go high or low and it's also possible to connect some of them to such things as the chips external interrupts. Ultimately, the button should generate an interrupt that can trigger a state change. For now, for proof of concept of the button, I will initially work on polling the state of a pin connected to GPIO.

Looking at the examples in the RealView Microcontroller Development Kit, the simplest example: "blinky" for the LPC family waggles GPIO pins. Running this example on the simulator in uVision allows me see the pins changing in the GPIO peripheral simulator as it runs. It seems that pretty much every peripheral on LPC is simulated apart from USB, so I won't have to move to real hardware for a while.

The blinky example certainly shows me how to change pins high and low under program control, but what I want to do is change program flow by changing pins high and low.

Looking at the LPC2148 manual tells me that the pins on the GPIO are configured for input by default and hooked to some of the external chips pins. Looking at the Pin Connect Block peripheral in the simulator in uVision verifies that this is the case.

From the user manual is see I can read the pins state by reading the IOPINn register. Running blinky again I find that by clicking on a pin in the GPIO peripheral dialog, I can change its state (provided it hasn't been configured for output -- the simulator complains if you try this, as it should). This is neat; it would take a fair bit of hacking for me to do this in real hardware. Some boards do add buttons to GPIO, true, but I don't want to get into that yet.

So I now have a crude way of changing a pins state on the chip which I can poll in my program. The following couple of Macros allow me to test the pin/button to see if it has been taken low:

#define PINMASK 0x00000001 /* Let's do pin 1 */
/* IF masked pin number is low THEN button pressed */
#define BUTTON_PRESSED ((IOPIN0 & PINMASK)== 0)


Saturday, July 01, 2006

LogStick new ui

Time to consider the software design of the LogStick and start writing some code. I have been considering where to start, and a good place seems to be the user interface! In the classic MVC paradigm the Model will be the logging, upload and download software, the Audio and LEDs will be the View and the Controller will be the one-button user interface. Well, actually the Controller would be a state machine whose state could be changed by the button and other things, such as being USB docked, timing out etc.

The fun bit with developing embedded software is that it is (for me at least) an oscillation between top-down and bottom-up design. Top-down, the highest level of this design is probably going to be a state machine. My first stab at the state machine from a button perspective is listed at the end of this posting.

Looking at it now in the cold light of posting, this seems rather broken to me since it doesn't cater for false starts in the field, for example. I will have a go at rewriting this shortly in a more readable syntax for those who aren't Smalltalk hackers and try to cater for a more real world scenario. Meanwhile: Bottom-up, I need a button to control the state changes in a state machine, so I'll try that next.

logStick button isPressed
ifTrue:[logStick docked
ifTrue:[logStick upLoading
ifFalse:[logStick empty. logStick setTime]]
ifFalse[logStick recorder isRecording
ifTrue:[logStick button isPressed
ifTrue:[logStick recorder stop]]
ifFalse:[logStick recorder begin]].