söndag 26 december 2010

Open source LPC17xx development

This summer I wanted to try something new in the microcontroller area and decided to advance from 8-bit AVR and PIC to 32-bit ARM. There is a jungle of ARM-based microcontrollers out there and deciding on which one is "the best" isn't very easy. I ended up choosing an NXP LPC17xx Cortex-M3 based micro controller since the price was fairly good and I found MicropendousX, an open hardware dev-board project with free open source schematics and pcb-layout in KiCad (free open source EDA-tool) format.
I used the 1758 version (Seems abandoned in favour for the 1768) but removed ethernet and redrew the layout using more hole-mounted components to make it easier to mount, probe and re-wire.

I will add the schematic and board files someday, hopefully soon...

The result:
Features:
A simple "Wiggler" parallel port programmer and OpenOCD works fine to program and debug the micro controller. I think I used the programmer described here but with a connector that fits my board.

The GNU toolchain I use is the arm-none-eabi lite edition of G++ from Codesourcery.

As an IDE I use Eclipse. Stepping through C and assembler code works like a charm. I think I used these instructions to get it working.

lördag 25 december 2010

Calling Cortex-M3 assembler function in RAM from gcc C

I needed a fast  function written in assembler and run from RAM. I thought the most simple way to do this without adding stuff to the linker script was to change the .text directive to .data (same as initialised variables). But the result of the change was a hard fault when the function got called.
The solution was to tell gcc it is a function with .type logic_sample_fast, %function
So the whole function looks like this:
.syntax unified
.cpu cortex-m3
.thumb
.data
.align 4

#define FIO0PIN                    (0x2009c014)
#define FIO1PIN                    (0x2009c034)
#define LOGIC_IN_FIOPIN_REG        FIO1PIN

.global logic_sample_fast
.type logic_sample_fast, %function
.thumb_func
logic_sample_fast:
    movw r1, :lower16:LOGIC_IN_FIOPIN_REG
    movt r1, :upper16:LOGIC_IN_FIOPIN_REG
    cpsid i
trig0:
    ldrb r2, [r1]
    ands r3, r2, #1
    bne trig0
trig1:
    ldrb r2, [r1]
    ands r3, r2, #1
    beq trig1
    .rept (40*8)
    ldrb r2, [r1]
    strb r2, [r0], #1
    .endr
    cpsie i
    bx lr
And the definition in C like this:
void logic_sample_fast(uint8_t *buffer);

fredag 30 juli 2010

ZRip - extract the Z code text adventure part of a zblorb file

The Z machine is a virtual machine used by Infocom in the 80's-90's so that they more easily could port their different text adventure games to the many different platforms of the time. The Z machine has its own instruction set called Z code. Some versions of the Z machine support images and sound.
IF-Archive contains many Z-code games playable on a Z machine.
The blorb-format is a format developed to collect the Z code, images and sound that were previously in separate files into one single file. (Btw, blorbs can contain code for other interpreters as well, not just Z code)
This is were ZRip comes in.
Blorbs can contain high resolution sound and images and become quite big and not suitable for machines with limited memory capacity. ZRip reads a blorb-file and tries to extract just the Z code.

Here's the source

onsdag 9 juni 2010

OpenOCD Ubuntu 8.10

sudo aptitude install libftdi1
sudo aptitude install libftdi-dev
./configure --enable-parport --with-ftd2xx-lib --enable-usbprog
make
sudo make install

onsdag 6 januari 2010

Computer controlled wall outlets

Got hold of three radio controlled wall outlets on sale. Modified the remote to be able to control the outlets with a pc parallel port (or some other port compatible with a 74xxx05)




The remote contains a sc2262 and is powered by a 12V battery.

After a look under the hood of the remote the conclusion was made that a press of a button connect two pins to ground, totally 5 pins are used giving six buttons (see schematic).
To control this from a computer a 74LS05 (hex inverter with open collector outputs) was used (any 7405 should do but if it's going to be powered by the parallel port it won't hurt using a low power one), connecting the open collector outputs directly to the control chip. The 7405 is powered using bit 5,6 and 7 of the data port, this is enough using the parallel port on my motherboard.


Schematic:




inside (the white wire is the antenna)



To control the parallel port this small (linux) program is used, ppdev module has to be loaded.


Remote.c
//Control of remote to remote controlled wall outlets using the parallel port
//Written for linux
//Written by Mikael Ågren 2009
//
//gcc remote.c -o remote

#include <stdlib.h>
#include <stdio.h>
#include <sys/io.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
#include <fcntl.h>

int fd;

//map bits of pp data port
#define PWR    (1<<7)|(1<<6)|(1<<5)    //used to power buffer
#define ROD    1<<0
#define LILA    1<<1
#define GUL    1<<2
#define VIT    1<<3
#define SVART    1<<4

#define ON    ROD
#define OFF    LILA
#define ONE    GUL
#define TWO    VIT
#define THREE    SVART

unsigned char setParPortData(unsigned char data) {
    ioctl(fd, PPDATADIR, 0);
    if(ioctl(fd, PPWDATA, &data)) {
        printf("error writing to port");
        exit(2);
    }
}

delay_enough() {
    char i;
    for(i=0; i<5; i++) {
        delay_1s();
    }
}

delay_1s() {
    time_t t;
    time_t old_t;

    old_t = time(NULL);
    while ((t=time(NULL)) < old_t+1) {
    }
}

void printHelp(char **argv, int exitcode) {
    printf("usage: %s reciever on|off\nreciever = 1, 2 or 3\n", argv[0]);
    exit(exitcode);
}

int main(int argc, char **argv)
{
    if(argc!=3) {
        printHelp(argv, 1);
    }

    printf("Försöker öppna /dev/parport0\n");
    fd = open("/dev/parport0", O_RDONLY);
    if(ioctl(fd, PPCLAIM)) {
        perror ("PPCLAIM");
        close(fd);
        return 1;
    }
    printf("/dev/parport0 öppnad\n");

    unsigned char out=0;
    //which reciever
    if(!strcmp(argv[1], "1"))
        out |= ONE;
    else if(!strcmp(argv[1], "2"))
        out |= TWO;
    else if(!strcmp(argv[1], "3"))
        out |= THREE;
    else
        printHelp(argv, 1);
    //which state
    if(!strcmp(argv[2], "on"))
        out |= ON;
    else if(!strcmp(argv[2], "off"))
        out |= OFF;
    else
        printHelp(argv, 1);
    //keep buffer powered
    out |= PWR;

    printf("%x\n", PWR);    
    setParPortData(PWR);
    delay_enough();    
    printf("%x\n", out);    
    setParPortData(out);
    delay_enough();    
    printf("%x\n", 0);    
    setParPortData(0);

    close(fd);
    return 0;
}

Coffee...
Wrote some simple scripts so i can wake up to the smell and sound of fresh coffee in the morning

kaffeON
remote 3 on

kaffeOFF
remote 3 off

kaffe
if [ "$1" = "" ];
then
        echo "usage:    $0 now"
        echo "  $0 HH:MM"
        exit -1
fi

timeoff=$(date -d "$1 30 min" +%H:%M)
$(echo kaffeOFF | at $timeoff)

if [ "$1" = "now" ];
then
        void=$(kaffeON)
        echo $void
else
        timeon="$1"
        $(echo kaffeON | at $timeon)
fi