Basis for the C2 protocol from Silicon Labs.

Dependencies:   mbed

main.cpp

Committer:
Ivop
Date:
2014-05-25
Revision:
5:53d4a67cd657
Parent:
4:a9e3ee5741be
Child:
6:deb670cb8105

File content as of revision 5:53d4a67cd657:

/*
 * SiLabs C2 Protocol on mbed pins p5/p6
 *
 * Copyright (c) 2014, Ivo van Poorten <ivopvp@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
#include "mbed.h"

DigitalOut c2ck(p5);
DigitalInOut c2d(p6);

static struct devices {
    char *name;
    int devid;
} devices[] = {
    { "F30x",                  0x04 },
    { "F31x",                  0x08 },
    { "F32x",                  0x09 },
    { "F326/7",                0x0d },
    { "F33x",                  0x0a },
    { "F336/7",                0x14 },
    { "F34x",                  0x0f },
    { "F35x",                  0x0b },
    { "F36x",                  0x12 },
    { "F38x",                  0x28 },
    { "F39x/F37x",             0x2b },
    { "F41x",                  0x0c },
    { "F50x/F51x",             0x1c },
    { "F52xA/F53xA",           0x11 },
    { "F54x",                  0x21 },
    { "F55x/F56x/F57x",        0x22 },
    { "F58x/F59x",             0x20 },
    { "F70x/F71x",             0x1e },
    { "F80x/F81x/F82x/F83x",   0x23 },
    { "F90x/F91x",             0x1f },
    { "F92x/F93x",             0x16 },
    { "F96x",                  0x2a },
    { "F99x",                  0x25 },
    { "T60x",                  0x10 },
    { "T606",                  0x1b },
    { "T61x",                  0x13 },
    { "T62x/T32x",             0x18 },
    { "T622/T623/T326/T327",   0x19 },
    { "T63x",                  0x17 },
    { NULL, 0 }
};

#define C2_DEVID    0
#define C2_REVID    1
#define C2_FPCTL    2
static int C2_FPDAT = 0xb4;         // or 0xad
static int page_size = 512;         // not seen 4096 yet

static void c2ck_reset(void) {
    c2ck = 0;
    wait_us(25);
    c2ck = 1;
    wait_us(1);
}

static void c2ck_strobe(void) {
    c2ck = 0;
    wait_us(1);
    c2ck = 1;
    wait_us(1);
}

// Four basic C2 Instructions
//
// 00b  Data Read
// 01b  Data Write
// 10b  Address Read
// 11b  Address Write
//
// Remember, ALL fields are sent LSB first(!)

#define START       do{ c2ck_strobe(); }while(0)
#define STOP        START
#define INS(a,b)    do{ c2d = a; c2ck_strobe(); c2d = b; c2ck_strobe(); }while(0)
#define LENGTH(a,b) INS(a,b)
#define WAIT        do{\
        while(t-- && !c2d) {    \
            c2ck_strobe();      \
            wait_us(1);         \
        } if (!t) return -1;    \
    } while(0)
#define READV       do{\
    for (i=0; i<8; i++) {       \
        v >>= 1;                \
        c2ck_strobe();          \
        if (c2d) v |= 0x80;     \
    } } while(0)
#define WRITEV      do{\
    for(i=0; i<8; i++) {        \
        c2d = v & 1;            \
        c2ck_strobe();          \
        v >>= 1;                \
    } } while(0)

static int c2_read_dr(void) {
    int t = 20, i, v = 0;
    
    START;
    c2d.output();
    INS(0,0);
    LENGTH(0,0);    
    c2d.input();
    WAIT;    
    READV;
    STOP;
    
    return v;
}

static int c2_write_dr(int v) {
    int t = 20, i;
    
    START;
    c2d.output();
    INS(1,0);
    LENGTH(0,0);
    WRITEV;
    c2d.input();
    WAIT;
    STOP;
    
    return 0;
}

static int c2_read_ar(void) {
    int i, v = 0;
    
    START;
    c2d.output();
    INS(0,1);
    c2d.input();
    READV;
    STOP;

    return v;
}

static void c2_write_ar(int v) {
    int i;

    START;
    c2d.output();
    INS(1,1);
    WRITEV;
    c2d.input();
    STOP;
}

static void fatal(char *s) {
    puts(s);
    exit(1);
}

int main() {
    int i, c, devid, revid;
    
    c2d.input();
    c2ck = 1;

    printf("\033[H\033[J");
    printf("SiLabs C2 Protocol\n\r\n\r");
    printf("Connect C2CK (clock) to p5 and C2D (data) to p6\n\r\n\r");
    printf("Press any key to continue\n\r");

    getc(stdin);

    c2_write_ar(C2_DEVID);
    devid = c2_read_dr();
    if (devid <= 0) fatal("unable to read devid\n\r");
    
    c2_write_ar(C2_REVID);
    revid = c2_read_dr();
    if (revid < 0) fatal("unable to read revid\n\r");

    for (i=0; devices[i].name; i++) {
        if (devices[i].devid == devid) break;
    }
    
    if (!i) {
        printf("unknown device: %02X:%02X\n\r", devid, revid);
        fatal("unable to continue\n\r");
    }

    switch(devid) {
        case 0x0f: case 0x28: case 0x18: case 0x19: C2_FPDAT = 0xad;
        default: break;
    }

    printf("\n\rDevice found: %s (%02X:%02X)", devices[i].name, devid, revid);
    printf("\n\rFPDAT Address: 0x%02X", C2_FPDAT);
    printf("\n\rPage Size: %i\n\r", page_size);
}