Basis for the C2 protocol from Silicon Labs.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * SiLabs C2 Protocol on mbed pins p5/p6
00003  *
00004  * Copyright (c) 2014, Ivo van Poorten <ivopvp@gmail.com>
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00017  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00018  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00019  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00020  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00021  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00022  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00023  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00025  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027  
00028 #include "mbed.h"
00029 #include <stdarg.h>
00030 #include <stdio.h>
00031 #include <stdint.h>
00032 
00033 DigitalOut c2ck(p5);
00034 DigitalInOut c2d(p6);
00035 
00036 static uint8_t buffer[256];
00037 
00038 static struct devices {
00039     char *name;
00040     int devid;
00041 } devices[] = {
00042     { "F30x",                  0x04 },    { "F31x",                  0x08 },
00043     { "F32x",                  0x09 },    { "F326/7",                0x0d },
00044     { "F33x",                  0x0a },    { "F336/7",                0x14 },
00045     { "F34x",                  0x0f },    { "F35x",                  0x0b },
00046     { "F36x",                  0x12 },    { "F38x",                  0x28 },
00047     { "F39x/F37x",             0x2b },    { "F41x",                  0x0c },
00048     { "F50x/F51x",             0x1c },    { "F52xA/F53xA",           0x11 },
00049     { "F54x",                  0x21 },    { "F55x/F56x/F57x",        0x22 },
00050     { "F58x/F59x",             0x20 },    { "F70x/F71x",             0x1e },
00051     { "F80x/F81x/F82x/F83x",   0x23 },    { "F90x/F91x",             0x1f },
00052     { "F92x/F93x",             0x16 },    { "F96x",                  0x2a },
00053     { "F99x",                  0x25 },    { "T60x",                  0x10 },
00054     { "T606",                  0x1b },    { "T61x",                  0x13 },
00055     { "T62x/T32x",             0x18 },    { "T622/T623/T326/T327",   0x19 },
00056     { "T63x",                  0x17 },    { NULL, 0 }
00057 };
00058 
00059 #define C2_MASK_FLBUSY      0x80
00060 #define C2_MASK_INBUSY      0x02
00061 #define C2_MASK_OUTREADY    0x01
00062 
00063 // Programming Interface (PI) Commands
00064 
00065 #define C2_PI_CMD_GET_VERSION       0x01
00066 #define C2_PI_CMD_GET_DERIVATIVE    0x02
00067 
00068 #define C2_PI_CMD_DEVICE_ERASE      0x03
00069 
00070 #define C2_PI_CMD_BLOCK_READ        0x06        // FLASH (max. 64K bytes, bankswapping not supported)
00071 #define C2_PI_CMD_BLOCK_WRITE       0x07        // FLASH
00072 
00073 #define C2_PI_CMD_PAGE_ERASE        0x08
00074 
00075 #define C2_PI_CMD_DIRECT_READ       0x09        // SFR (Special FUnction Registers, 256 bytes(?))
00076 #define C2_PI_CMD_DIRECT_WRITE      0x0a        // SFR
00077 
00078 #define C2_PI_CMD_INDIRECT_READ     0x0b        // RAM (Internal, 256 bytes)
00079 #define C2_PI_CMD_INDIRECT_WRITE    0x0c        // RAM
00080 
00081 #define C2_PI_CMD_XRAM_READ         0x0e        // RAM (External, 2K or 4K bytes)
00082 #define C2_PI_CMD_XRAM_WRITE        0x0f        // RAM
00083 
00084 // PI Status Values
00085 #define C2_PI_STATUS_COMMAND_INVALID    0x00
00086 #define C2_PI_STATUS_NO_CONNECT         0x01
00087 #define C2_PI_STATUS_FAILED             0x02
00088 #define C2_PI_STATUS_PAGE_LOCKED        0x03    // "security" feature
00089 #define C2_PI_STATUS_TIMEOUT            0x04
00090 #define C2_PI_STATUS_BAD_DATA           0x05
00091 #define C2_PI_STATUS_OK                 0x0d
00092 
00093 // C2 Registers
00094 #define C2_REG_DEVID    0
00095 #define C2_REG_REVID    1
00096 #define C2_REG_FPCTL    2
00097 static int C2_REG_FPDAT = 0xb4;         // or 0xad
00098 static int page_size = 512;
00099 
00100 static void fatal(char *f, ...) {
00101     va_list ap;
00102     va_start(ap,f);
00103     printf("\r\nFATAL: ");
00104     vprintf(f, ap);
00105     va_end(ap);
00106     exit(1);
00107 }
00108 
00109 static void c2ck_reset(void) {
00110     c2d.input();
00111     c2ck = 0;
00112     wait_us(25);
00113     c2ck = 1;
00114     wait_us(3);
00115 }
00116 
00117 static void c2ck_strobe(void) {
00118     c2ck = 0;
00119     wait_us(1);
00120     c2ck = 1;
00121     wait_us(1);
00122 }
00123 
00124 // Remember, ALL fields are sent LSB first(!)
00125 
00126 #define START       do{ c2ck_strobe(); }while(0)
00127 #define STOP        START
00128 #define INS(a,b)    do{ c2d = a; c2ck_strobe(); c2d = b; c2ck_strobe(); }while(0)
00129 #define LENGTH(a,b) INS(a,b)
00130 #define WAIT        c2ck_strobe(); do{\
00131         while(!c2d && t--) {    \
00132             c2ck_strobe();      \
00133             wait_us(1);         \
00134         } if (!t) return -1;    \
00135     } while(0)
00136 #define READV       do{\
00137     for (i=0; i<8; i++) {       \
00138         v >>= 1;                \
00139         c2ck_strobe();          \
00140         if (c2d) v |= 0x80;     \
00141     } } while(0)
00142 #define WRITEV      do{\
00143     for (i=0; i<8; i++) {        \
00144         c2d = v & 1;            \
00145         c2ck_strobe();          \
00146         v >>= 1;                \
00147     } } while(0)
00148 
00149 static int c2_read_dr(void) {
00150     int t = 20, i, v = 0;
00151     
00152     START;
00153     c2d.output();
00154     INS(0,0);
00155     LENGTH(0,0);    
00156     c2d.input();
00157     WAIT;    
00158     READV;
00159     STOP;
00160     
00161     return v;
00162 }
00163 
00164 static int c2_write_dr(int v) {
00165     int t = 20, i;
00166     
00167     START;
00168     c2d.output();
00169     INS(1,0);
00170     LENGTH(0,0);
00171     WRITEV;
00172     c2d.input();
00173     WAIT;
00174     STOP;
00175     
00176     return 0;
00177 }
00178 
00179 static int c2_read_ar(void) {
00180     int i, v = 0;
00181     
00182     START;
00183     c2d.output();
00184     INS(0,1);
00185     c2d.input();
00186     READV;
00187     STOP;
00188 
00189     return v;
00190 }
00191 
00192 static void c2_write_ar(int v) {
00193     int i;
00194 
00195     START;
00196     c2d.output();
00197     INS(1,1);
00198     WRITEV;
00199     c2d.input();
00200     STOP;
00201 }
00202 
00203 static int poll_status(int mask) {
00204     int t = 20, s;
00205     do {
00206         s = c2_read_ar();
00207         if (mask == C2_MASK_INBUSY) {
00208             if (!(s & mask)) return 0;
00209         } else {
00210             if (s & mask)    return 0;
00211         }
00212         wait_us(1);
00213     } while(--t);
00214     return -1;
00215 }
00216 
00217 static void c2_enable_pi(void) {
00218     c2ck_reset();
00219     wait_ms(2);
00220     c2_write_ar(C2_REG_FPCTL);
00221     if ((c2_write_dr(0x02))<0)
00222         fatal("cannot enable PI (wr2)");
00223     if ((c2_write_dr(0x04))<0)
00224         fatal("cannot enable PI (wr4)");
00225     if ((c2_write_dr(0x01))<0)
00226         fatal("cannot enable PI (wr1)");
00227     wait_ms(25);
00228 }
00229 
00230 static int c2_read_mem(int type, int address, int size, uint8_t *buf) {
00231     int ret, i, ram_or_sfr = (type == C2_PI_CMD_DIRECT_READ) || (type == C2_PI_CMD_INDIRECT_READ);
00232 
00233     c2_write_ar(C2_REG_FPDAT);
00234     c2_write_dr(type);
00235 
00236     if (poll_status(C2_MASK_INBUSY) < 0)
00237         fatal("read_mem: cannot set FPDAT, no input ACK");
00238     if (poll_status(C2_MASK_OUTREADY) < 0)
00239         fatal("read_mem: cannot set FPDAT, no output ready");
00240 
00241     ret = c2_read_dr();
00242     if (ret != C2_PI_STATUS_OK)
00243         fatal("read_mem: status not OK after setting FPDAT (status %02X)", ret);
00244 
00245     if (!ram_or_sfr) {
00246         c2_write_dr((address >> 8)&0xff);
00247         if (poll_status(C2_MASK_INBUSY) < 0)
00248             fatal("read_mem: cannot write msb of address");
00249     }
00250 
00251     c2_write_dr(address & 0xff);
00252     if (poll_status(C2_MASK_INBUSY) < 0)
00253         fatal("read_mem: cannot write lsb of address");
00254 
00255     c2_write_dr(size&0xff);
00256     if (poll_status(C2_MASK_INBUSY) < 0)
00257         fatal("read_mem: cannot set block length");
00258     if (poll_status(C2_MASK_OUTREADY) < 0)
00259         fatal("read_mem: no data ready");
00260 
00261     ret = c2_read_dr();
00262     if (ret != C2_PI_STATUS_OK)
00263         return ret;
00264     
00265     for (i=0; i<size; i++) {
00266         if (poll_status(C2_MASK_OUTREADY) < 0)
00267             fatal("read_mem: no data ready during retrieval of block");
00268         buf[i] = c2_read_dr();
00269     }
00270     
00271     return C2_PI_STATUS_OK;
00272 }
00273 
00274 int main() {
00275     int i, c, devid, revid, ret;
00276     
00277     c2d.input();
00278     c2ck = 1;
00279 
00280 //    printf("\033[H\033[J");
00281     printf("\r\nSiLabs C2 Protocol\r\n\r\n");
00282     printf("Connect C2GND to GND, C2CK (clock) to p5 and C2D (data) to p6\r\n\r\n");
00283     printf("Press any key to continue\r\n");
00284 
00285     getc(stdin);
00286 
00287     c2_write_ar(C2_REG_DEVID);
00288     devid = c2_read_dr();
00289     if (devid <= 0) fatal("unable to read devid\r\n");
00290     
00291     c2_write_ar(C2_REG_REVID);
00292     revid = c2_read_dr();
00293     if (revid < 0) fatal("unable to read revid\r\n");
00294 
00295     for (i=0; devices[i].name; i++) {
00296         if (devices[i].devid == devid) break;
00297     }
00298     
00299     if (!i) fatal("unknown device: %02X:%02X\r\n", devid, revid);
00300 
00301     switch(devid) {
00302         case 0x0f: case 0x28: case 0x18: case 0x19: C2_REG_FPDAT = 0xad;
00303         default: break;
00304     }
00305 
00306     printf("\r\nDevice found: %s (%02X:%02X)", devices[i].name, devid, revid);
00307     printf("\r\nFPDAT Address: 0x%02X", C2_REG_FPDAT);
00308     printf("\r\nPage Size: %i\n\r", page_size);
00309     
00310     printf("\r\nEnabling Programming Interface\r\n");
00311     c2_enable_pi();
00312 
00313     for (c=0; c<256; c++) {
00314         printf("\r\nReading page %i\r\n", c);
00315         ret = c2_read_mem(C2_PI_CMD_BLOCK_READ, c<<8, 0x100, buffer);
00316         if (ret == C2_PI_STATUS_OK) {
00317             for (i=0; i<0x100; i++) {
00318                 printf("%02x ", buffer[i]);
00319                 if (i%16 == 15) printf("\r\n");
00320             }
00321         } else {
00322             if (ret == C2_PI_STATUS_PAGE_LOCKED)
00323                 printf("page is locked, ");
00324             printf("read failed\r\n");
00325         }
00326     }
00327 }