TS-4200 PC104 example

From Technologic Systems Manuals

With the baseboards that make use of the PC104 bus, you must first set up the MUXBUS configuration registers. From Debian, you would run this:

source /initrd/ts4200.subr 
pc104on

NOTE: The `pc104on` command sets the MUXBUS timing config register to 0x181, which is aggressive timing. This may not work for all PC/104 devices, in which case we recommend writing a more conservative config value, something like `peekpoke 16 0x30000020 0x381`

From your application you can now talk to the MUXBUS for communication to PC104. The TS-4200 with our baseboards will implement the 8 bit PC104 address space from 0x10000400 to 0x100007ff. The 16 bit access is available from 0x30000400 to 0x300007fe. This example uses the TS-RELAY8.

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <assert.h>

// This offset is for the TS-4200 8bit SMC (FPGA)
#define BASE_ADDRESS 0x10000000

// This assumes jumper 1 is on the TS-RELAY8
#define PLD_OFFSET 0x140

unsigned short *muxbus_base;
typedef enum {
  RLYON = 0x00,
  RLYOFF = 0xFF,
  RLY1 = 1 << 0,
  RLY2 = 1 << 1,
  RLY3 = 1 << 2,
  RLY4 = 1 << 3,
  RLY5 = 1 << 4,
  RLY6 = 1 << 5,
  RLY7 = 1 << 6,
  RLY8 = 1 << 7
} RelayFlags;

static void poke8(unsigned int adr, uint8_t val) {
        muxbus_base[adr / 2] = val;
}

void set_relays(RelayFlags bits) {
    // This adds the PLD offset to talk to the TS-RELAY8
    // the 0x400 is the offset for the MUXBUS (see the FPGA Functionality section)
    // 0x2 is added for the offset of the actual relays.  See the TS-RELAY8 wiki for more details
    poke8(PLD_OFFSET + 0x400 + 0x2, bits);
    usleep(15000);
}

int main(int argc, char **argv) {
    int mem = open("/dev/mem", O_RDWR|O_SYNC);
    assert(mem != -1);
    muxbus_base = mmap(0,
         getpagesize(),
         PROT_READ|PROT_WRITE,
         MAP_SHARED,
         mem,
         BASE_ADDRESS);
    assert(muxbus_base != MAP_FAILED);

    while(1)
    {
	set_relays(RLYOFF);
        set_relays(RLY1);
        set_relays(RLY1|RLY2);
        set_relays(RLY1|RLY2|RLY3);
        set_relays(RLY1|RLY2|RLY3|RLY4);
        set_relays(RLY1|RLY2|RLY3|RLY4|RLY5);
        set_relays(RLY1|RLY2|RLY3|RLY4|RLY5|RLY6);
        set_relays(RLY1|RLY2|RLY3|RLY4|RLY5|RLY6|RLY7);
        set_relays(RLYON);
    }
    return 0;
}