Programming of the DDS-60 (AD9851) frequency synthesizer from AmQRP http://midnightdesignsolutions.com/dds60/index.html I had to use long, floating math in order to get accurate frequency output.

Dependencies:   TextLCD mbed ChaNFS

Files at this revision

API Documentation at this revision

Comitter:
loopsva
Date:
Wed Apr 04 18:14:54 2012 +0000
Commit message:
050511

Changed in this revision

AD9851/AD9851.cpp Show annotated file Show diff for this revision Revisions of this file
AD9851/AD9851.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS.lib Show annotated file Show diff for this revision Revisions of this file
SDHCFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDHCFileSystem.h Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbedADC/adc.cpp Show annotated file Show diff for this revision Revisions of this file
mbedADC/adc.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AD9851/AD9851.cpp	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,217 @@
+#include "mbed.h"
+#include "AD9851.h"
+
+extern int gDebug;                      // defined in main.cpp, used for printing verbose-ness level (0-3)
+//extern double StepFreq;                 // step frequency (used for gDebug lines only)
+
+// power up default values
+double BaseFreq = 10000000.000;         // base frequency - if frequency
+double IfFreq = 455000.0;               // IF frequency
+double RealFreq = BaseFreq + IfFreq;    // sum of the two frequencies
+double RefOsc = 30000000.000;           // reference oscillator frequency
+char MultSix = 'A';                     // x1 or x6 frequency oscillator - 0, 1 or A only
+bool ErrorFlag = false;                 // error flag
+bool FirstEnable = false;               // used for DDS-60 bug fix
+
+double OldBaseFreq = BaseFreq;          // old base frequency - if frequency
+double OldIfFreq = IfFreq;              // old IF frequency
+char OldMultSix = MultSix;              // old x1 or x6 frequency oscillator - 0, 1 or A only
+
+double SerCount = 1431655765.0;         // calculated final value of data to AD9851
+unsigned int FreqDiv = 0x55555555;      // calculated value of SerCount to be divided into SerData[0-4]
+
+const char LsbPhase = 0x08;             // LSB of phase setting, 0-31 (0-0x1f), 11.25 degrees per step
+const char PwrDnFlag = 0x04;            // + power down flag
+const char Mult6Flag = 0x01;            // + 180MHz - 30MHz multiplier x6 flag
+char FortyBitWd = PwrDnFlag + (LsbPhase * 1); // calculated 5th byte fo 40 bit word to be divided into SerData[0-4]
+    
+// constructor takes paramters and initializes I2C bus
+AD9851::AD9851(PinName CLK, PinName SDO, PinName LEN)
+      : _clk(CLK)
+      , _sdo(SDO)
+      , _len(LEN) 
+    {
+    _clk = 0;
+    _sdo = 0;
+    _len = 0;
+    OutNewValue();                      // initialize the AD9851
+}
+
+// destructor
+AD9851::~AD9851() {
+}
+
+// return base frequency value
+double AD9851::GetBaseValue() {
+    return BaseFreq;
+}
+
+// return IF frequency value
+double AD9851::GetIfValue() {
+    return IfFreq;
+}
+
+// return 32 serial word value
+unsigned int AD9851::GetFD32Value() {
+    return FreqDiv;
+}
+
+// return 5th "control" byte for 40 bit serial word value
+char AD9851::GetFortyValue() {
+    return FortyBitWd;
+}
+
+// return error flag
+bool AD9851::GetErrFlagValue() {
+    return ErrorFlag;
+}
+
+//---------------------------------------------------------------
+// set base frequency value
+double AD9851::SetBaseValue(double bv) {
+    if(bv >= 0.0) {
+        BaseFreq = bv;
+    } else {
+        printf("Base neg number!!!\n");
+    }
+    return(bv);
+}
+
+// set IF frequency value
+double AD9851::SetIfValue(double bv) {
+    if(bv >= 0.0) {
+        IfFreq = bv;
+    } else {
+        printf("IF neg number!!!\n");
+    }
+    return(bv);
+}
+    
+// set base frequency value, ascii 0 1 or A
+char AD9851::SetM6Value(char bx) {
+    MultSix = bx;
+    return(bx);
+}
+    
+//---------------------------------------------------------------
+// turn on AD9851
+void AD9851::AD9851Enable() {
+    FortyBitWd = FortyBitWd & (-1-(PwrDnFlag));
+    FirstAccess();
+//    OutNewValue();
+}
+
+// turn off AD9851
+void AD9851::AD9851Disable() {
+    FirstEnable = false;
+    FortyBitWd = FortyBitWd | PwrDnFlag;
+    OutNewValue();
+}
+
+// calculate new value based on change.  If an over frequency condition exists, then resort back to original values
+bool AD9851::CalcNewValue() {
+    RealFreq = BaseFreq + IfFreq;
+    ErrorFlag = false;
+    if(RealFreq >= 0.0) {    // error if RealFreq is negative number
+        if(((RealFreq >= RefOsc) && (MultSix == '0')) || (((RealFreq >= (RefOsc * 6.0)) && ((MultSix == '1') || (MultSix == 'A') || (MultSix == 'a'))))) { 
+            //error if >30MHz and multiplier = 0     
+            //error if >180MHz and multiplier = 1 or A
+            ErrorFlag = true;
+            BaseFreq = OldBaseFreq;
+            IfFreq = OldIfFreq;
+            RealFreq = BaseFreq + IfFreq;
+            MultSix = OldMultSix;
+        } else {
+            OldBaseFreq = BaseFreq;
+            OldIfFreq = IfFreq;
+            RealFreq = BaseFreq + IfFreq;
+            OldMultSix = MultSix;
+            if((MultSix == '0') || ((MultSix == 'A') && (RealFreq < RefOsc))) { //less than 30MHz
+                SerCount = 1.0 / (RefOsc / 4294967296.0 / RealFreq);            // 4294967296 = 2^32
+                FortyBitWd = FortyBitWd & (-1-(Mult6Flag));
+//                if(gDebug > 1) printf("1- m6: %c  rF: %f  sF: %f  40bw: 0x%02x  sc: %f\n  ref: %f", MultSix, RealFreq, StepFreq, FortyBitWd, SerCount, RefOsc);
+            } else {                                                            //less than 180MHz
+                SerCount = 1.0 / ((RefOsc * 6.0) / 4294967296.0 / RealFreq);
+                FortyBitWd = FortyBitWd | Mult6Flag;
+//                if(gDebug > 1) printf("2- m6: %c  rF: %f  sF: %f  40bw: 0x%02x  sc: %f\n", MultSix, RealFreq, StepFreq, FortyBitWd, SerCount);
+            }
+            FreqDiv = (unsigned int)SerCount; 
+            if(gDebug > 1) printf("3- out: 0x%02x%08x\n", FortyBitWd, FreqDiv);
+            OutNewValue(); 
+        }
+    } else {
+        printf("calc neg number!!!\n");
+        ErrorFlag = true;
+    }
+    if(gDebug) printf("\nBase: %.3f  IF: %.3f  Freq: %.3f  Mult: %c  Out: 0x%02x%08x\n", BaseFreq, IfFreq, RealFreq, MultSix, FortyBitWd, FreqDiv); 
+    return (ErrorFlag);
+}
+
+/* Private routines: */
+// set new value to AD9851
+void AD9851::OutNewValue() {
+    unsigned int ShiftOut = FreqDiv;
+    unsigned int TestOut = FreqDiv;
+    char i = 0;
+    for(i=0; i<32; i++) {
+        TestOut = ShiftOut & 1;
+        if(TestOut==1) {
+            _sdo = 1;
+        } else {
+            _sdo = 0;
+        }
+        _clk = 1;
+        ShiftOut = ShiftOut >> 1;
+        _clk = 0;
+    }
+    ShiftOut = FortyBitWd;
+    for(i=0; i<8; i++) {
+        TestOut = ShiftOut & 1;
+        if(TestOut==1) {
+            _sdo = 1;
+        } else {
+            _sdo = 0;
+        }
+        _clk = 1;
+        ShiftOut = ShiftOut >> 1;
+        _clk = 0;
+    }
+    _len = 1;
+    _len = 0;
+}
+
+// BUG FIX, on the very first access after an enable, first force 100KHz w/Mult6 = 0, set Mult6 = 1 forever
+void AD9851::FirstAccess() {
+    if(FirstEnable == false) {
+        FirstEnable = true;
+        unsigned int TempDiv = FreqDiv;
+        FreqDiv =0x00da740d;
+        char Temp40 = FortyBitWd;
+        FortyBitWd = 0x0c;
+        OutNewValue();
+        wait_ms(5);
+        FortyBitWd = Temp40;
+        FreqDiv = TempDiv;
+        SetM6Value(1);
+    }
+    CalcNewValue();
+}
+/*
+void AD9851::FirstAccess() {
+    if(FirstEnable == false) {
+        FirstEnable = true;
+        unsigned int TempDiv = FreqDiv;
+        FreqDiv =0;
+        char Temp40 = FortyBitWd;
+        FortyBitWd = 0x01;
+        OutNewValue();
+        wait_ms(5);
+        OutNewValue();
+        wait_ms(5);
+        FortyBitWd = Temp40;
+        FreqDiv = TempDiv;
+        SetM6Value(1);
+    }
+    CalcNewValue();
+}
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AD9851/AD9851.h	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,90 @@
+#ifndef AD9851_H
+#define AD9851_H
+
+#include "mbed.h"
+
+/** A AD9851 driver interface to control the DDS-60 from AmQRP
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "AD9851.h"
+ * 
+ * AD9851 freqSyn(p13, p14, p15);          //sdo, clk, len
+ * 
+ * int main() {
+ *     freqSyn.AD9851Enable();                  //turn on AD9851
+ *     freqSyn.AD9851Disable();                 //turn off AD9851
+ *
+ *     float Fdata;
+ *     Fdata = freqSyn.GetBaseValue();          //get Base frequency
+ *     Fdata = freqSyn.GetIfValue();            //get IF offset frequency
+ *
+ *     freqSyn.SetBaseValue(7320000.0);         //set new Base frequency (0.0 - 179,999,999.999MHz)
+ *     freqSyn.SetIfValue(1620000.0);           //set new IF frequency (0.0 - 179,999,999.999MHz)
+ *     freqSyn.SetM6Value('A');                 //set multiplier value 0 = 30MHz max, 6 = 180MHz max, A = auto 
+ *
+ *     //functions below are results from CalcNewValue()
+ *     bool ErFlag;
+ *     ErFlag = freqSyn.CalcNewValue();         //calculate new AD9851 value, based on Base, IF and M6 values
+ *                                              //if ok, new value output to AD9851
+ *                                              //note: reverts to old values if Base + IF * M6 is over limit, sets error flag
+ *                                              //ERROR occured with new values used by CalcNewValue()
+ *
+ *     ErFlag = freqSyn.GetErrFlagValue();      //get error value from last time CalsNewValue() was executed
+ *   
+ *     unsigned int UIdata; 
+ *     UIdata = freqSyn.GetFD32Value();         //get 32 bit hex value of AD9851 data
+ *   
+ *     char Cdata;
+ *     Cdata = freqSyn.GetFortyValue();         //get 8 bit hex value of AD9851 control register (enable & M6). Phase offset always 0
+ * }
+ * @endcode
+ */
+
+class AD9851 /*: public Stream*/ { // or  : public Base
+
+public:
+/** Create a frequency selector object 
+    * @param SDO serial data out
+    * @param CLK serial clock - data clocked on + edge
+    * @param LEN data latch enable strobe - high pulse after all 40 bits of data clocked in
+    */
+    AD9851(PinName SDO, PinName CLK, PinName LEN);
+
+//  Destroys object
+    ~AD9851();
+
+//  Returns the stored Base Freq, IF Freq, 32 bit serial word and 5th control byte values    
+    double GetBaseValue();
+    double GetIfValue();
+    unsigned int GetFD32Value();
+    char GetFortyValue();
+    bool GetErrFlagValue();
+
+//  Set values   
+    double SetBaseValue(double bv);
+    double SetIfValue(double bv);
+    char SetM6Value(char bx);
+
+//  Turn the AD9851 on / off    
+    void AD9851Enable();
+    void AD9851Disable();
+    
+
+//  calculates new AD9851 value - returns to old values if error occurs, sets error flag
+    bool CalcNewValue();
+    
+protected:
+    DigitalOut _clk, _sdo, _len;  
+    double bv; 
+    char bx;
+        
+private:
+
+//  transfers new 40 bit word to the AD9851
+    void OutNewValue();
+    void FirstAccess();
+
+
+};    
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS.lib	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/NeoBelerophon/code/ChaNFS/#629e4be333f3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDHCFileSystem.cpp	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,495 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+ /*
+ * Comment: Changes for SDHC support till 32GB 
+ * Name:    KB
+ * Date:    07/24/2010
+ * Release: 0.1
+ */
+ 
+#include "SDHCFileSystem.h"
+
+#define DEBUG
+#define SD_COMMAND_TIMEOUT 5000
+
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            cdv = 512;
+            #ifdef DEBUG 
+            printf("Init: SEDCARD_V1\n");
+            #endif
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        wait_ms(50);
+        _cmd58();
+        _cmd(55, 0); 
+        if(_cmd(41, 0x40000000) == 0) { 
+            _cmd58();
+            #ifdef DEBUG
+            printf("Init: SDCARD_V2\n");
+            #endif
+            cdv = 1;
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+    #ifdef DEBUG 
+    printf("init card = %d\n", i);
+    #endif
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(1000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * cdv) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    int c_size, c_size_mult, read_bl_len;
+    int block_len, mult, blocknr, capacity;       
+    int blocks, hc_c_size;
+    uint64_t hc_capacity;
+     
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+   
+    int csd_structure = ext_bits(csd, 127, 126);
+    
+    #ifdef DEBUG 
+    printf("CSD_STRUCT = %d\n", csd_structure);
+    #endif
+     
+    switch (csd_structure){
+     case 0:
+      cdv = 512;
+      c_size = ext_bits(csd, 73, 62);
+      c_size_mult = ext_bits(csd, 49, 47);
+      read_bl_len = ext_bits(csd, 83, 80);
+     
+      block_len = 1 << read_bl_len;
+      mult = 1 << (c_size_mult + 2);
+      blocknr = (c_size + 1) * mult;
+      capacity = blocknr * block_len;
+      blocks = capacity / 512;
+      #ifdef DEBUG 
+      printf("SDCard\n\rc_size: %.4X \n\rcapacity: %.ld \n\rsectors: %d\n", c_size, capacity, blocks);
+      #endif
+      break;
+    
+     case 1:
+      cdv = 1;
+      hc_c_size = ext_bits(csd, 63, 48);
+      int hc_read_bl_len = ext_bits(csd, 83, 80);
+      hc_capacity = hc_c_size+1;   
+      blocks = (hc_c_size+1)*1024;
+      #ifdef DEBUG 
+      printf("SDHC Card \n\rhc_c_size: %.4X \n\rcapacity: %.lld \n\rsectors: %d\n", hc_c_size, hc_capacity*512*1024, blocks);
+      #endif
+      break;
+   
+    default:    
+       fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+     return 0;
+     break;
+    };
+ return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDHCFileSystem.h	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,86 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDHCFILESYSTEM_H
+#define MBED_SDHCFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/* Double Words */
+typedef unsigned long long uint64_t;
+typedef long long sint64_t;
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs; 
+    int cdv;    
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/TextLCD/#44f34c09bd37
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,1199 @@
+/*
+Rev Date        Changes:
+------------------------------------------------------------------------------------------------------------------------------------------
+100 5/06/11     - putting things together, first cut
+101 5/10/11     - removed G command from menu
+                - added AD9851 on/off to summary
+102 5/11/11     - added file dds60.ini, initializes file if missing 
+                - reads dds60.ini at boot up to get frequency values
+                - added ability to store current values in dds60.ini into local memory using new W command
+103 5/12/11     - tried a new fix for signal quality problem. wouldn't start above 30MHz, went back to 102 version
+                - most commands now use a single keystroke vs waiting for a CR
+104 5/17/11     - removed i/o delays in ad9851.cpp. results in a 40 bit download to ad9851 in 10.4uS - was 1.24mS
+105 6/08/11     - added "listdir" function
+
+------------------------------------------------------------------------------------------------------------------------------------------
+Known issues:
+                - Signal quality is bad between 200KHz and 30MHz
+102               Patch fix in AD9851.cpp, routine void AD9851::FirstAccess()
+105             - "listdir" function works, but "listdirSD" function doesn't
+
+------------------------------------------------------------------------------------------------------------------------------------------
+*/
+
+int revision = 105;                     // revision of this code
+#include "mbed.h"
+#include "SDHCFileSystem.h"
+#include "adc.h"
+#include "FATFileSystem.h"
+//#include "MSCFileSystem.h"
+#include "TextLCD.h" 
+#include "AD9851.h"
+//#include "MODSERIAL.h"
+//#define TX_PIN p13 //p9 p13 or p28
+//#define RX_PIN p14 //p10 p14 or p27
+#define SAMPLE_RATE    150000       //for A:D converter
+
+#define CLS "\033[2J"
+extern "C" void mbed_reset();
+extern "C" void mbed_mac_address(char *);
+#define DEFAULTHOSTNAME "mbed-c3p1"
+char *hostname = DEFAULTHOSTNAME;
+
+LocalFileSystem local("local");
+
+PwmOut led1(LED1, "led1");
+DigitalOut led2(LED2, "led2");
+DigitalOut led3(LED3, "led3");
+DigitalOut led4(LED4, "led4");
+I2C i2c(p9, p10);                       // sda, scl
+TextLCD lcdt(p24, /*p25, */p26, p27, p28, p29, p30, TextLCD::LCD16x2); // rs, rw, e, d0, d1, d2, d3
+DigitalOut LCDrw(p25, "LCDrw");         // new LCD code no longer requries R/W pin - tie low (J5 on Orange Board"
+Serial/*MODSERIAL*/  pc(USBTX, USBRX);                // Serial USB communications over mbed USB port
+//MODSERIAL uart(TX_PIN, RX_PIN);
+SDFileSystem sd(p5, p6, p7, p8, "sd");  // mosi, miso, sclk, cs
+AD9851 dds60(p16, p17, p15);          //clk, sdo, len
+
+
+
+// Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1
+int gDebug = 1;                         // display debog level (0 - 3)
+int OldgDebug = gDebug;                 // copy of gDebug for updating kb-mbed.ini
+int DST = 0;                            // Daylight Saving Time (or as defined in kb-mbed.ini)
+int OldDST = DST;                       // Copy of DST for updating kb-mbed.ini
+int TZone = -8;                         // Time Zone from UTC (or as defined in kb-mbed.ini)
+int OldTZone = TZone;                   // copy for updating kb-mbed.ini
+int NTPUpdateValue = 86400;             // update RTC every 24 hours (or as defined in kb-mbed.ini)
+int bootDHCP = 1;                       // boot DHCP(1) of fixed IP(0) (or as defined in kb-mbed.ini)
+float Press0Ft = 102.4;                 // altimeter - assumed pressure at sea level
+float Saved0Ft = Press0Ft;              // saved for later comparison if changed by HTTP
+float OldPress0Ft = Press0Ft;           // another copy for updating kb-mbed.ini
+char mac[6];                            // mbed MAC address
+
+float Led1Pwm = 0.01;                   // LED1 brightness
+bool Led1Up = true;                     // LED1 auto up-down
+
+ADC adc(SAMPLE_RATE, 1);
+bool use_sd = false;                    // flag for using SDHC file system
+bool ZeroMinFlag = false;               // alignment to 00:00:00 flag
+float gWait = 0.005;                    // Main loop wait timeout
+float const DISP_SLOW(2.0);             // Long wait for LCD display
+float const DISP_FAST(0.5);             // Faster wait for LCD
+int i2cQty = 16;                        // number of bytes to get
+char i2cData[130];                      // i2c read buffer data
+
+double LclBaseFreq = 1000000.0;         // base frequency - if frequency
+double LclIfFreq = 262000.0;            // IF frequency
+double StepFreq = 1000.0;               // increment/decrement step frequency
+double OldStepFreq = StepFreq;          // old copy of increment/decrement step frequency
+
+int pcRxQty = 0;                        // MODSER RX data counter/pointer
+char pcRxData[20];                      // MODSER RX data buffer
+char inchar = 0;                        // RX input character
+const char BS = 0x08;                   // ascii backspace
+const char CR = 0x0d;                   // ascii CR
+const char LF = 0x0a;                   // ascii LF
+const char SP = 0x20;                   // ascii space
+const char ESC = 0x1b;                  // ascii escape
+const char DP = 0x2e;                   // ascii decimal point / period
+const char ticC = 0x0c;                 // ascii control C
+bool pcRxLine = false;                  // CR or LF detected in RX buffer
+bool pcRxEOB = false;                   // RX buffer EOB (full)
+bool pcRxIsNumb = false;                // whether or not string is a valid number (including dp)
+bool ErFlag = false;                    // error flag
+bool FirstAccess = false;               // very first DDS60 access
+double pcRxNumb = 0.0;                  // RX buffer comversion
+char Fcmd = 0;                          // post RX processing command decoder
+unsigned int SerialNum[5] = {58,0,0,0,0}; // mbed serial number data
+
+int Tic = 0;                            // Tic counter to update LCD sequence
+int Sequence = 0;                       // LCD step through sequence counter
+
+
+
+/*----------*/
+void disp_i2c() {
+    lcdt.cls();
+    lcdt.locate(0,0);         //column(0-15), row(0-1)
+    lcdt.printf("I2CU! Searching\n");
+    lcdt.locate(0,1);         //column(0-15), row(0-1)
+    lcdt.printf("for I2C devices");
+//    pc.printf("\n\n");
+    pc.printf("I2CU! Searching for I2C devices...\n");
+    wait(DISP_FAST);
+
+    int count = 0;
+    for (int address=2; address<256; address+=2) {
+        if (!i2c.write(address, NULL, 0)) { // 0 returned is ok
+/* A one time write to all detected EEPROM chips for later identification */
+/*            i2cData[0] = 0;         // pointer register (hi)
+            i2cData[1] = 0;         // pointer register (lo)
+            i2cData[2] = count+1;   // detected i2c device (in sequence 1-128)
+            i2cData[3] = address;   // device's i2c address
+            i2cData[4] = count;     // device number (0-3)
+            int i = 5;
+            for (i=5; i<(5+5*8); i+=5) {
+                i2cData[i] = 0;         // next available write address (highest Hamming nibble) init to 0x0080
+                i2cData[i+1] = 0;       // next available write address, Hamming nibble 2 of 4
+                i2cData[i+2] = 0x8b;    // next available write address, Hamming nibble 3 of 4
+                i2cData[i+3] = 0;       // next available write address, Hamming nibble 4 of 4
+                i2cData[i+4] = 0;       // clear out address pointer flags byte (0x07 = 1 or more of the 4 bytes above is wore out)
+            }
+            for (i=i+5; i<130; i+=1) {  //clear out remainder of buffer area
+                i2cData[i] = 255;
+            }
+*/
+            
+/****** The following line inititalizes the EEPROMs to the structure above ******/
+//            (!i2c.write(address, i2cData, 132));  // store device address at location 0
+            
+            wait(0.005);
+            pc.printf("-I2C device found at address 0x%02X\n", address);
+            for (int clrb=0; clrb<i2cQty; clrb+=1) {  //clear out i2c buffer before reading in data
+                i2cData[clrb] = 0;
+            }
+            // If device is a 24fc1025, then set the pointer register
+            if (address>0x9F && address<0xB0) {     // do only if accessing EEPROM
+                i2cData[0] = 0;                     // point to location 0 in EEPROM
+                i2cData[1] = 0;
+                (!i2c.write(address, i2cData, 2));  // set location 0 in EEPROM
+            }
+            // If device is a temperature sensor (adt7410, then reset device and set 16 bit mode
+/*            if (address>0x8F && address<0x91) {     // do only if accessing Temp sensor
+                pc.printf("-Initializing ADT7410...\n");
+                ADT7410Up = true;                   // set "installed" flag
+//                i2cData[0] = 0x2f;                  // point to location 0x2f (reset reg) in Temp
+//                (!i2c.write(address, i2cData, 1));  // reset temperature device
+
+                fever.reset();
+                wait_ms(1);
+//                fever.setConfig(char 0x82);
+//                i2cData[0] = 0x03;                  // point to location 0x03 (config reg) in Temp
+//                i2cData[1] = 0x82;                  // 16 bit mode, 3 faults
+//                (!i2c.write(address, i2cData, 2));  // set config register
+//                wait_ms(1);
+                i2cData[0] = 0x0b;                  // point to location 0x0b (id register)
+                (!i2c.write(address, i2cData, 1));  // set pointer for before read
+                i2cData[0] = 0x00;                  // point to location 0
+//                (!i2c.write(address, i2cData, 1));  // set pointer for before read
+                (!i2c.read(address, i2cData, 1));   // get ID
+                TempId = i2cData[0];                // save ID
+                pc.printf(" id: %02x\n", TempId);
+
+            }
+            // If device is a MPL115A2, then set the pointer register
+            if (address>0xBF && address<0xC2) {     // do only if accessing MPL115
+                MPL115aUp = true;                   // set "installed" flag
+                i2cData[0] = 0x12;                  // start a temp / baro conversion
+                i2cData[1] = 0x01;
+                (!i2c.write(address, i2cData, 2));  // set location 0x12 in MPL115
+                pc.printf("-Initializing MPL115A2...\n");
+                wait_ms(6);                         // need 6mS for conversions
+                i2cData[0] = 0;                     // point to location 0 in MPL115
+                i2cData[1] = 0;
+                (!i2c.write(address, i2cData, 1));  // set location 0 in MPL115
+            }
+            // Read and display first 16 bytes of 'found' device
+            (!i2c.read(address, i2cData, i2cQty));  // get first few bytes from device
+            if (address>0xBF && address<0xC2) {     // do only if accessing MPL115
+                baro.initBaroCoef();    //initializes coeficents - only do once after reset
+                baro.getBaroKPa();     //first real pressure access
+//                baro.getBaroRegs();     //displays all coef registers
+//                baro.getBaroCoef();     //displays all of the coeficent values
+            }
+            */
+            pc.printf(" ");
+            for (int ptr=0; ptr<i2cQty/2; ptr+=1) {  // print them out
+                pc.printf("%02x ",i2cData[ptr]);
+            }
+            pc.printf("  ");
+            for (int ptr=i2cQty/2; ptr<i2cQty; ptr+=1) {  // print them out
+                pc.printf("%02x ",i2cData[ptr]);
+            }
+            pc.printf("   ");
+            for (int ptr=0; ptr<i2cQty; ptr+=1) {  // print them out
+                if (i2cData[ptr]>32 && i2cData[ptr]<127) {   // do ascii if legal character
+                    pc.printf("%c",i2cData[ptr]);
+                }
+                else {
+                    pc.printf(".");
+                }
+            }
+            pc.printf("\n");
+            count++;
+/*            if (address>0x8F && address<0x91) {     // do only if accessing Temp sensor
+                printf("ADT7410 config: 0x%x\n", fever.getConfig());
+//                TempC = fever.getTemp();
+//                TempF = TempC * 9.0 / 5.0 + 32.0;
+//                printf("Temperature %.3fC   %.3fF\n", TempC, TempF);
+            }
+            */
+        }
+    }
+    if (count == 0) pc.printf("    ");
+    pc.printf("I2CU! %d devices found\n", count);
+    lcdt.cls();
+    lcdt.locate(0,0);         //column(0-15), row(0-1)
+    lcdt.printf("I2CU! found...\n");
+    lcdt.locate(0,1);         //column(0-15), row(0-1)
+    lcdt.printf("%d devices\n", count);
+} 
+
+/* save values in file sensors.csv for later retreval */
+/*
+void storeValues() {
+    time_t cstTime;                                             //need our own time stamp
+    cstTime = time(NULL);                                       //get time stamp
+    cstTime = cstTime + ((TZone + DST) * 3600);                 //set to local date
+    strftime(timebuf_d, 32, "%m/%d/%y,", localtime(&cstTime));  //format date
+    strftime(timebuf, 32, "%H:%M:%S,", localtime(&cstTime));    //format time
+            
+    if(use_sd == false) {                                       //use local or sd file system?
+        if(ZeroMinFlag == true) {                               //only do once an hour if local 
+            if (gDebug > 1) pc.printf("   Looking for /local/sensors.csv\n");
+            FILE *fp = fopen("/local/sensors.csv", "r");
+            if (fp == NULL) {
+                pc.printf("\n***Creating /local/sensors.csv\n");
+                FILE *fp = fopen("/local/sensors.csv", "w");
+                if (fp == NULL) {
+                    pc.printf("***cannot create /local/sensors.csv !!!\n");
+                    return;                                         //exit with create error
+                } else {
+                    fprintf(fp, "date,time,inHg,kPa,deg F,deg C, alt F,kPa @ 0\n");
+                    fclose(fp);
+                }
+            } else {
+                fclose(fp);                                         //close as a read or create file
+                if (gDebug > 1) pc.printf("Saving data in /local/sensors.csv ...");
+                FILE *fp = fopen("/local/sensors.csv", "a");        //re-open as an append file
+                fputs(timebuf_d, fp);                               //save date
+                fputs(timebuf, fp);                                 //dave time
+                fprintf(fp, "%2.2f,%3.1f,%3.2f,%2.2f,%5.0f,%3.1f\n", 
+                    RollAvgPress * kPa_inHg, 
+                    RollAvgPress, 
+                    RollAvgTemp * 9.0 / 5.0 + 32.0, 
+                    RollAvgTemp, 
+                    RollAltitude / 0.3048, 
+                    Press0Ft); 
+                fclose(fp);
+                if (gDebug > 1) pc.printf(" done\n");
+            }
+        }
+    } else {                                                    // SDHC available to use
+        if (gDebug > 1) pc.printf("   Looking for /sd/sensors.csv\n");
+        FILE *fp = fopen("/sd/sensors.csv", "r");
+        if (fp == NULL) {
+            pc.printf("\n***Creating /sd/sensors.csv\n");
+            FILE *fp = fopen("/sd/sensors.csv", "w");
+            if (fp == NULL) {
+                pc.printf("***cannot create /sd/sensors.csv !!!\n");
+                return;                                         //exit with create error
+            } else {
+                fprintf(fp, "date,time,inHg,kPa,deg F,deg C, alt F,kPa @ 0, Zero Hr\n");
+                fclose(fp);
+            }
+        } else {
+            fclose(fp);                                         //close as a read or create file
+            if (gDebug > 1) pc.printf("Saving data in /sd/sensors.csv ...");
+            FILE *fp = fopen("/sd/sensors.csv", "a");           //re-open as an append file
+            fputs(timebuf_d, fp);                               //save date only
+            fputs(timebuf, fp);                                 //save time only
+            fprintf(fp, "%2.2f,%3.1f,%3.2f,%2.2f,%5.0f,%3.1f", 
+                RollAvgPress * kPa_inHg, 
+                RollAvgPress, 
+                RollAvgTemp * 9.0 / 5.0 + 32.0, 
+                RollAvgTemp, 
+                RollAltitude / 0.3048, 
+                Press0Ft); 
+                if(ZeroMinFlag == true) {
+                    fprintf(fp, ",****\n");
+                } else { 
+                    fprintf(fp, "\n"); 
+                }
+            fclose(fp);
+            if (gDebug > 1) pc.printf(" done\n");
+        }
+    }
+}
+*/
+/*----------*/
+// print "local" directory
+void listdir(void) {
+    pc.printf("/local directory:\n");
+    DIR *d;
+    struct dirent *p;
+
+    d = opendir("/local");
+    if (d != NULL) {
+        while ((p = readdir(d)) != NULL) {
+            printf(" - %s\n", p->d_name);
+        }
+    } else {
+        pc.printf("Could not open -local- directory!\n");
+    }
+    closedir(d);
+}
+/*----------*/
+// print "sd" directory ***broken!!
+/*
+void listdirSD(void) {
+    pc.printf("/sd directory:\n");
+    DIR *d;
+    struct dirent *p;
+
+    d = opendir("/sd");
+    if (d != NULL) {
+        while ((p = readdir(d)) != NULL) {
+            printf(" - %s\n", p->d_name);
+        }
+    } else {
+        printf("Could not open -sd- directory!\n");
+    }
+    closedir(d);
+}
+*/
+/*----------*/
+void getMbedSN() {
+    unsigned int SerialNum[5] = {58,0,0,0,0};
+    typedef void (*CallMe)(unsigned int[],unsigned int[]);
+    CallMe CallMe_entry=(CallMe)0x1FFF1FF1;
+    CallMe_entry(SerialNum, SerialNum);
+    if (!SerialNum[0])
+        pc.printf("mbed serial number is: %0.8x %0.8x %0.8x %0.8x\n", 
+            SerialNum[1], SerialNum[2], SerialNum[3], SerialNum[4]);
+    else
+        pc.printf("***Unable to retrieve Serial Number from LPC Flash\n");
+}
+
+/* display MAC address */
+void getMbedMAC() {
+//    uint64_t uid = 0;
+////    char mac[6];
+    mbed_mac_address(mac);
+//    uid = mac[0] << 40 | mac[1] << 32 |
+//          mac[2] << 24 | mac[3] << 16 |
+//          mac[4] << 8  | mac[5] << 0;   
+    pc.printf("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);      
+}
+
+/* initialize dds60 configuration file if it doesn't already exist */
+void InitIniFile() {
+    FILE *fp = fopen("/local/dds60.ini", "w");
+    if (fp == NULL) {
+        pc.printf("***Cannot create dds60.ini file!!!\n");
+    } else {
+        if(gDebug) pc.printf("***Updating/Creating dds60.ini file...   \n");
+        fprintf(fp, "# DDS-60 configuration file\r\n");
+        fprintf(fp, "\r\n[Freqs]\r\n");
+        fprintf(fp, "BaseFrequency=%f\r\n",LclBaseFreq);
+        fprintf(fp, "IFFrequency=%f\r\n", LclIfFreq);
+        fprintf(fp, "StepFrequency=%f\r\n", StepFreq);
+
+        fprintf(fp, "\r\n[Global]\r\n");
+        fprintf(fp, "Timezone(hrs)=%d\r\n", TZone);
+        fprintf(fp, "DstZone(hrs)=%d\r\n", DST);
+        fprintf(fp, "NTPRefresh(sec)=%d\r\n", NTPUpdateValue);
+        fprintf(fp, "gDebugLevel=%d\r\n", gDebug);
+        fprintf(fp, "\r\n##END\r\n");
+        fclose(fp);
+        if(gDebug) pc.printf("   done\n");
+    }
+    OldgDebug = gDebug;
+    OldDST = DST;
+    OldTZone = TZone;
+    OldPress0Ft = Press0Ft;
+}
+
+// Trim whitespace/CRLFs from both ends of a given string
+// for use with routine below
+char * str_cleanup(char *in) {
+    char * out = in;
+    // Trim leading spaces and CR/LF
+    while (*out == ' ' || *out == '\t' || *out == '\r' || *out == '\n')
+        out ++;
+    // Trim trailing spaces and CR/LF
+    int len = strlen(out)-1;
+    while (out[len] == ' ' || out[len] == '\t' || out[len] == '\r' || out[len] == '\n') {
+        out[len] = '\0';
+        len--;
+    }
+    return out;
+}
+
+// Simple ini file parser for SNTP configuration (Case-sensitive!)
+// This function is intended to be called only before SNTPClientInit().
+// Returns: 0 if OK, errno otherwise
+enum {
+  SECT_NONE,
+  SECT_FREQS,
+  SECT_GLOBAL,
+};
+
+//int _SNTPClrAddresses();
+
+int SNTPReadIniFile(const char* filename) {
+    if (gDebug > 1) pc.printf("Before: tz:%d  dst:%d ntpupd:%d baroZ:%.1f name:%s\n", TZone, DST, NTPUpdateValue, Press0Ft, hostname);
+    FILE *f;
+    char buf[512];
+//    bool addresses_cleared = false;
+    bool hname = false;
+    f = fopen(filename, "r");
+    if (!f)
+        return -1;    // errno not used?
+    char *buf1, *buf2;
+    int section=SECT_NONE;
+    int line = 0;
+    while (fgets(buf, sizeof(buf)/sizeof(buf[0]), f)) {
+        line++;
+        buf1 = str_cleanup(buf);
+        if (*buf1 == '#' || *buf1 == '\0')
+            continue;    // Comment line or empty line - skip
+        if (*buf1 == '[') {
+            // New section
+            if (0 == strncmp(buf1,"[Freqs]", sizeof("[Freqs]")-1)) {
+                section=SECT_FREQS;
+/*                if (!addresses_cleared) {
+                    // Clear addresses only once.
+                    _SNTPClrAddresses();
+                    addresses_cleared = true;
+                }
+*/            } else if (0 == strncmp(buf1,"[Global]", sizeof("[Global]")-1)) {
+                section=SECT_GLOBAL;
+            } else {
+                section=SECT_NONE;
+                fprintf(stderr, "***File \"%s\", line %d - section \"%s\" is not understood.\r\n", filename, line, buf1);
+            }
+        } else {
+            // Section values
+            switch (section) {
+            case SECT_FREQS:
+                buf2 = strchr(buf1, '=');
+                if (buf2) {
+                    *buf2++ = '\0';     // Now buf1 has variable name, buf2 has value
+                    buf2 = str_cleanup(buf2);
+                    if (0 == strncmp(buf1, "BaseFrequency", sizeof("BaseFrequency")-1)) {
+                        LclBaseFreq = strtof(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "IFFrequency", sizeof("IFFrequency")-1)) {
+                        LclIfFreq = strtof(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "StepFreq", sizeof("StepFreq")-1)) {
+                        StepFreq = strtod(buf2, &buf2);
+                    } else {
+                        pc.printf("***File \"%s\", line %d - unrecognized variable \"%s\" in section [Freqs]\r\n", filename, line, buf1);
+                    }
+                } else {
+                    pc.printf("***File \"%s\", line %d - unrecognized statement in section [Freqs]: %s\r\n", filename, line, buf1);
+                }
+                break;
+            case SECT_GLOBAL:
+                buf2 = strchr(buf1, '=');
+                if (buf2) {
+                    *buf2++ = '\0';     // Now buf1 has variable name, buf2 has value
+                    buf2 = str_cleanup(buf2);
+                    if (0 == strncmp(buf1, "Timezone(hrs)", sizeof("Timezone(hrs)")-1)) {
+                        TZone = strtod(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "NTPRefresh(sec)", sizeof("NTPRefresh(sec)")-1)) {
+                        NTPUpdateValue = strtod(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "gDebugLevel", sizeof("gDebugLevel")-1)) {
+                        gDebug = strtod(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "bootDHCP", sizeof("bootDHCP")-1)) {
+                        bootDHCP = strtod(buf2, &buf2);
+                    } else if (0 == strncmp(buf1, "MyName", sizeof("MyName")-1)) {
+                        if (hname == false) {
+                            hname = true;
+                            hostname = buf2;
+                            if (gDebug > 1) pc.printf("buf2:%s hn:%s\n", buf2, hostname);
+                        }
+                    } else if (0 == strncmp(buf1, "PressureSeaLevel", sizeof("PressureSeaLevel")-1)) {
+                        Press0Ft = strtof(buf2, &buf2);
+                    //} else if (0 == strncmp(buf1, "RtcUtc", sizeof("RtcUtc")-1)) {
+                     //   gSntpRtcUtc = (bool)strtol(buf2, &buf2, 10);
+                    } else if (0 == strncmp(buf1, "DstZone(hrs)", sizeof("DstZone(hrs)")-1)) {
+                        DST = strtod(buf2, &buf2);
+                    } else {
+                        pc.printf("***File \"%s\", line %d - unrecognized variable \"%s\" in section [Global]\r\n", filename, line, buf1);
+                    }
+                } else {
+                    pc.printf("***File \"%s\", line %d - unrecognized statement in section [Global]: %s\r\n", filename, line, buf1);
+                }
+                break;
+            default:
+                pc.printf("***File \"%s\", line %d - unrecognized statement / no section: %s\r\n", filename, line, buf1);
+            }
+        }
+    }
+    fclose(f);
+    pc.printf("DDS60 configuration read from \"%s\", %d lines.\r\n", filename, line);
+    pc.printf("- gDebug display level: %d\n", gDebug);
+    pc.printf("- Time Zone: %d hours\n", TZone);
+    //pc.printf("- Daylight Saving Time - ");
+    if (DST == 0) {
+        pc.printf("- Standard Time\n");
+    } else {
+        pc.printf("- Daylight Saving Time\n");
+    }
+    pc.printf("- NTC update: %d seconds\n", NTPUpdateValue);
+    if (bootDHCP == 1) {
+        pc.printf("- booting HTTP, host name: %s\n", hostname);
+    } else {
+        pc.printf("- booting static IP\n");
+    }
+    
+    pc.printf("- Base Frequency: %.3f kPa\n", LclBaseFreq);
+    pc.printf("- IF Frequency:   %.3f kPa\n", LclIfFreq);
+    pc.printf("- Step Frequency: %.3f kPa\n", StepFreq);
+    
+//    if (gDebug > 1) pc.printf("After: tz:%d  dst:%d ntpupd:%d baroZ:%.1f name:%s\n", TZone, DST, NTPUpdateValue, Press0Ft, hostname);
+
+    OldgDebug = gDebug;
+    OldDST = DST;
+    OldTZone = TZone;
+    OldPress0Ft = Press0Ft;
+    dds60.SetBaseValue(LclBaseFreq);
+    dds60.SetIfValue(LclIfFreq);
+    dds60.CalcNewValue();
+    OldStepFreq = StepFreq;
+    return 0;
+}
+
+//update LCD based on Sequence count
+void UpdLCD() {
+    double Fdata = 0.0;
+    int UIdata = 0;
+    char Cdata = 0;
+    if(Sequence == 0) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("DDS-60 %d", revision);
+        lcdt.locate(0,1);                       //column(0-15), row(0-1)
+        lcdt.printf("K Braun");
+    }
+    if(Sequence == 1) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("(%d) Base Freq:", Sequence);
+        lcdt.locate(0,1);                       //column(0-15), row(0-1)
+        Fdata = dds60.GetBaseValue();
+        lcdt.printf("   %.3f", Fdata);
+    }
+    if(Sequence == 2) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("(%d) IF Freq:", Sequence);
+        lcdt.locate(0,1);                       //column(0-15), row(0-1)
+        Fdata = dds60.GetIfValue();
+        lcdt.printf("   %.3f", Fdata);
+    }
+    if(Sequence == 3) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("(%d) Step Freq:", Sequence);
+        lcdt.locate(0,1);                       //column(0-15), row(0-1)
+        lcdt.printf("   %.3f", StepFreq);
+    }
+    if(Sequence == 4) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("(%d) AD9851 data:", Sequence);
+        lcdt.locate(0,1);                       //column(0-15), row(0-1)
+        UIdata = dds60.GetFD32Value();    
+        Cdata = dds60.GetFortyValue();    
+        lcdt.printf("   0x%02x%08x\n", Cdata, UIdata);
+    }
+    if(Sequence == 5) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        if(ErFlag == false) {
+            lcdt.printf("DDS-60 %d", revision);
+            lcdt.locate(0,1);                       //column(0-15), row(0-1)
+            lcdt.printf("K Braun");
+        } else {
+            lcdt.printf("(%d) Entry Error", Sequence);
+            lcdt.locate(0,1);                       //column(0-15), row(0-1)
+            lcdt.printf("   !!!!!!!!");
+        }
+    }
+    if(Sequence > 5) {
+        lcdt.cls();
+        lcdt.locate(0,0);                       //column(0-15), row(0-1)
+        lcdt.printf("(%d) huh??", Sequence);
+    }
+}
+
+// manu selection menu
+void mainMenu() {
+    pc.printf("\n**************************************************************************\n");
+    pc.printf("                              MAIN MENU\n");
+    double Fdata;
+    Fdata = dds60.GetBaseValue();    
+    pc.printf("AD9851 Summary:\nBase Freq: %.3f\n", Fdata);
+    Fdata = dds60.GetIfValue();    
+    pc.printf("IF Freq:   %.3f\n", Fdata);
+    pc.printf("Step Freq: %.3f\n", StepFreq);
+    unsigned int UIdata;
+    UIdata = dds60.GetFD32Value();    
+    char Cdata;
+    Cdata = dds60.GetFortyValue();    
+    pc.printf("40 bit wd: 0x%02x%08x\n", Cdata, UIdata);
+    char onoff = Cdata & 0x04;
+    if(onoff == 0) {
+        pc.printf("AD9851 is: -ON-\n\n");
+    } else {
+        pc.printf("AD9851 is: -OFF-\n\n");
+    }
+//    pc.printf("----------\n");
+    pc.printf(" B - Base Frequency       Y - IF Frequency         S - Step Frequency\n");
+    pc.printf(" E - Enable DDS-60        X - Disable DDS-60\n");
+    pc.printf(" U - Update DDS-60        W - Write to Flash\n");
+    pc.printf(" I - Inc Step Frequency   D - Dec Step Frequency\n");
+    pc.printf(" R - Reboot!!!\n\n");
+//    pc.printf("\n");
+    pc.printf("**************************************************************************\n");
+    pc.printf("Selection: ");
+}
+
+// This function is called when a character goes from the TX buffer
+// to the Uart THR FIFO register.
+//void txCallback(MODSERIAL_IRQ_INFO *q) {
+//    led2 = !led2;
+//}
+
+// This function is called when TX buffer goes empty
+//void txEmpty(MODSERIAL_IRQ_INFO *q) {
+//    led2 = 0;
+//    pc.puts(" testing done...\n");
+//    lcdt.locate(0,1);                    //column(0-15), row(0-1)
+//    lcdt.printf("              ");       //print -me- on LCD
+//    lcdt.locate(0,1);                    //column(0-15), row(0-1)
+//    lcdt.printf("done");                //print -me- on LCD
+//}
+
+// This function is called when a character goes into the RX buffer.
+//void rxCallback(MODSERIAL_IRQ_INFO *q) {
+//    led3 = !led3;
+//    pc.putc(uart.getc());
+//}
+
+// This function is called when a character goes into the RX buffer.
+void Rx_interrupt() {
+//void rxCallbackpc(MODSERIAL_IRQ_INFO *q) {
+    inchar = pc.getc();
+//    led4 = !led4;
+    if(inchar == BS) { 
+        if(!pcRxQty == 0) {
+            pcRxData[pcRxQty] = 0;
+            pcRxQty = pcRxQty -1;
+        }
+    }
+    else if(inchar == CR) { 
+        pcRxLine = true;
+    }
+    else if(inchar == LF) {
+        pcRxLine = true;
+    } else {
+        if(pcRxQty < sizeof(pcRxData)) {
+            pcRxData[pcRxQty] = inchar;
+            pcRxQty = pcRxQty++; 
+//            pc.putc(inchar);
+        } else {
+//            pc.printf ("pcRxData is full!!\n");
+            pcRxEOB = true;
+        }
+    }
+}
+
+//clear RxData buffer with all 00's
+void pcClrLineBuf() {
+    pcRxQty = 0;                            // MODSER RX data counter/pointer
+    for(int i = 0; i < (sizeof(pcRxData) + 1); i++) {// clear out rx buffer
+        pcRxData[i] = 0;
+        pcRxLine = false;
+        pcRxEOB = false;
+        pcRxIsNumb = false;
+    }
+}
+// assemble a test line.  if it is a number, turn it into a double
+
+
+int loop = 0;        
+void higherDecode() {
+    double Fdata = 0.0;
+//    unsigned int UIdata;
+//    char Cdata;
+    if(pcRxLine == true) {                                      //data in rx buffer?
+        loop = loop++;
+        if(gDebug) pc.printf("loop: %d\n", loop);
+        if(pcRxQty == 1) {                                      //single alpha char?
+            if((pcRxData[0] == 'b') || (pcRxData[0] == 'B')) {             //enter Base frequency
+                Fdata = dds60.GetBaseValue();
+                pc.printf("\nBASE Frequency: %.3f  New: ", Fdata);
+                Fcmd = pcRxData[0] | 0x20;
+//                pcClrLineBuf();
+            } 
+            else if((pcRxData[0] == 'y') || (pcRxData[0] == 'y')) {        //enter IF frequency
+                Fdata = dds60.GetIfValue();
+                pc.printf("\nIF Frequency: %.3f  New: ", Fdata);
+                Fcmd = pcRxData[0] | 0x20;
+            }
+            else if((pcRxData[0] == 's') || (pcRxData[0] == 'S')) {        //enter step frequency value
+                pc.printf("\nStep Frequency: %.3f  New: ", StepFreq);
+                Fcmd = pcRxData[0] | 0x20;
+            }
+            else if((pcRxData[0] == 'r') || (pcRxData[0] == 'R')) {        //enable DDS-60
+                pc.printf("\nREBOOTING...\n");
+                wait(0.1);
+                mbed_reset();
+                mainMenu();
+            }
+            else if(pcRxIsNumb == false) {
+                pc.printf("2-huh???\n");
+                pcClrLineBuf();
+                mainMenu();
+            }
+        }
+    }
+    if((pcRxIsNumb == true) && (Fcmd == 'b')) {
+//        pc.printf("here-b ?\n");
+        dds60.SetBaseValue(pcRxNumb);
+//        pcClrLineBuf();
+        Fcmd = 0;
+        mainMenu();
+    }
+    else if((pcRxIsNumb == true) && (Fcmd == 'y')) {
+//        pc.printf("here-y ?\n");
+        dds60.SetIfValue(pcRxNumb);
+        pcRxIsNumb = false;
+        Fcmd = 0;
+        mainMenu();
+    }
+    else if((pcRxIsNumb == true) && (Fcmd == 's')) {
+//        if(gDebug > 1) pc.printf("1-sF: %.3f\n", StepFreq);
+        StepFreq = pcRxNumb;
+        if(StepFreq >= 0.0) {
+//            if(gDebug > 1) pc.printf("2-sF: %.3f\n", StepFreq);
+            pcRxIsNumb = false;
+        } else {
+            StepFreq = OldStepFreq;
+            pc.printf("Step neg number!!!\n");
+        }
+        Fcmd = 0;
+        mainMenu();
+    }
+    else if((pcRxIsNumb == true) && (!((Fcmd == 'b') || (Fcmd == 'y') || (Fcmd == 's')))) {
+        Fcmd = 0;
+        pcClrLineBuf();
+        mainMenu();
+    }
+    pcClrLineBuf();
+}
+
+
+void pcRx() {
+    double Fdata = 0.0;
+    if((pcRxData[0] == ESC) || (pcRxData[0] == ticC)) {            //kill? go back to main menu
+        wait_us(100);
+        pc.printf("\nblam!!!\n");
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'e') || (pcRxData[0] == 'E')) {        //enable DDS-60
+        pc.printf("\nEnabling AD9851...\n");
+        dds60.AD9851Enable();
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'x') || (pcRxData[0] == 'X')) {        //disable DDS-60
+        pc.printf("\nDisable AD9851...\n");
+        dds60.AD9851Disable();
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'w') || (pcRxData[0] == 'W')) {        //save values
+        pc.printf("\nWriting current values to Flash...\n");
+        LclBaseFreq = dds60.GetBaseValue();
+        LclIfFreq = dds60.GetIfValue();
+        InitIniFile();
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'u') || (pcRxData[0] == 'U')) {        //update DDS-60
+        ErFlag = dds60.CalcNewValue();
+        if(ErFlag == true) {
+            pc.printf("\nfrequency overflow error(1)!!\n");
+        } else {
+            pc.printf("\nUpdating AD9851...\n");
+            LclBaseFreq = dds60.GetBaseValue();
+            LclIfFreq = dds60.GetIfValue();
+        }
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'i') || (pcRxData[0] == 'I')) {        //increment DDS-60 frequency by step value
+        Fdata = dds60.GetBaseValue();
+        Fdata = Fdata + StepFreq;
+        dds60.SetBaseValue(Fdata);
+        ErFlag = dds60.CalcNewValue();
+        if(ErFlag == true) {
+            pc.printf("\nfrequency overflow error(2)!!\n");
+        } else {
+            pc.printf("\nStepping up freq...\n");
+            LclBaseFreq = dds60.GetBaseValue();
+            LclIfFreq = dds60.GetIfValue();
+        }
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if((pcRxData[0] == 'd') || (pcRxData[0] == 'D')) {        //decrement DDS-60 frequency by step value
+        Fdata = dds60.GetBaseValue();
+        Fdata = Fdata - StepFreq;
+        dds60.SetBaseValue(Fdata);
+        ErFlag = dds60.CalcNewValue();
+        if(ErFlag == true) {
+            pc.printf("\nfrequency overflow error(3)!!\n");
+        } else {
+            pc.printf("\nStepping down freq...\n");
+            LclBaseFreq = dds60.GetBaseValue();
+            LclIfFreq = dds60.GetIfValue();
+        }
+        pcClrLineBuf();
+        pcRxLine = false;
+        pcRxEOB = false;
+        mainMenu();
+    }
+    else if(pcRxLine == true) {
+//        pcRxLine = false;
+//        pc.printf("  -CR/LF- det  count:%d  size:%d\n", pcRxQty, sizeof(pcRxData));
+        if(pcRxQty == 0) {
+            wait_us(100);
+            pc.printf("empty...\n");
+            pcClrLineBuf();
+            mainMenu();
+        } else {
+            bool OneDot = false;
+            pcRxIsNumb = true;
+            for(int x = 0; x < pcRxQty; x++) {
+                char p = pcRxData[x];
+                if(pcRxIsNumb == true) {
+                    if(!((p == DP) || ((p >= '0') && (p <= '9')) || (pcRxData[0] == '-'))) {    //-not- 0-9 or DP ?
+                        pcRxIsNumb = false;
+                    }
+                    if((p == DP) && (pcRxQty == 1)) {                   //DP w/o numbers ?
+                        pcRxIsNumb = false;
+                    }
+                }
+                if((p == DP) && (OneDot == true) && (pcRxQty > 1)) {    //more than one DP?
+                    pcRxIsNumb = false;
+                }
+                if(p == DP) {                                           //one or more DP?
+                    OneDot = true;
+                }
+//                pc.printf("%c",p);
+            }
+        }
+        if(pcRxIsNumb == true) {
+            pcRxNumb = atof(pcRxData);
+//            pc.printf("valid number: %f\n", pcRxNumb);
+//            pcClrLineBuf();
+        }
+        higherDecode();
+        pcClrLineBuf();
+//        pc.printf("\n");
+    }
+    else if(pcRxEOB == true) {
+        pcRxEOB = false;
+        pc.printf("RxBuff max'd out!!\n");
+    }
+    else if(inchar == SP) {
+//        pc.printf("  -SP- det\n");
+        inchar = 0;
+    }
+}
+
+/*********************************************************************************************/
+int main() {
+    pc.baud(921600);                        //set up USB serial speed
+    i2c.frequency(400000);                  //set up i2c speed
+   
+    pcRxQty = 0;                            // MODSER RX data counter/pointer
+    pcClrLineBuf();                         // initialize pcRxData
+    
+    lcdt.cls();                             //init the LCD
+    lcdt.locate(0,0);                       //column(0-15), row(0-1)
+    lcdt.printf("DDS-60 %d", revision);     //print revision on LCD
+    lcdt.locate(0,1);                       //column(0-15), row(0-1)
+    lcdt.printf("K Braun");                 //print -me- on LCD
+    
+    pc.printf("\n\n");
+    pc.printf("-------------------------------------------------------------------\n");
+    pc.printf("DDS-60 Control Routines %d  K Braun\n", revision);
+    getMbedSN();                        //display mbed's serial number
+    getMbedMAC();                       //display mbed's MAC address
+    wait(DISP_SLOW);
+    dds60.SetM6Value('A');
+
+    // Check if we can use modify the http name of the mbed
+    FILE *fp = fopen("/local/whoami.ini", "r");
+//    char *hostname = DEFAULTHOSTNAME;
+    if (fp == NULL) {
+        pc.printf("    No /local/whoami.ini file, defaulting to:  %s\n",hostname);
+    } else {
+        char localbuf[64];
+        hostname = fgets(localbuf, sizeof(localbuf)-1, fp);
+        pc.printf("Found /local/whoami.ini file. my name is:  %s\n",hostname);
+        fclose(fp);
+    }
+    
+    FILE *fpi = fopen("/local/dds60.ini", "r");
+    if (fpi == NULL) {
+        InitIniFile();
+        pc.printf("***rebooting after file creation....");
+        wait(2.0);
+        mbed_reset();
+    } else {
+        pc.printf("Found /local/dds60.ini file...\n");
+        fclose(fpi);
+        SNTPReadIniFile("/local/dds60.ini");
+    }
+    if (gDebug) listdir();              //get local file listing
+// broken!!!    if (gDebug) listdirSD();            //get sd file listing
+//
+//NOTE:  mbed hangs if no SD card installed - need to fix!!!!!!
+//    
+    lcdt.cls();                          //init the LCD
+    lcdt.locate(0,0);                    //column(0-15), row(0-1)
+    lcdt.printf("SD Card Missing!");     //---in case SD drive hangs forever---
+        
+/*See if INDEX.HTM can be created on SD micro drive */
+    if (gDebug > 3) {
+//        char *WriteTest = "This is a Test!!!";
+        fp = fopen("/sd/INDEX.HTM", "w+");
+        if (fp == NULL) {
+            pc.printf("***Cannot create INDEX.HTM file\n");
+        } else {
+//            char localbuf[32];
+//            localbuf = WriteTest;
+            fprintf(fp, "This is a Test!!!\n");
+            pc.printf("Creating /sd/INDEX.HTM file\n");
+            fclose(fp);
+        }
+    }
+        
+    fp = fopen("/sd/index.htm", "r");
+    if (fp == NULL) {
+        use_sd = false;
+        if (gDebug) pc.printf("***No INDEX.HTM file - using LocalFilesystem for WebServer.\r\n");
+    } else {
+        use_sd = true;
+        fclose(fp);
+        if (gDebug) pc.printf("Found SD card with INDEX.HTM file - using SD for WebServer.\r\n");
+    }
+  
+    if ((use_sd == true) && (gDebug > 3)) pc.printf(" ");  // to get rid of use_sd "never used" warning
+  
+    disp_i2c();                         //display all devies on I2C bus
+    pc.printf("gDebug level: %d\n", gDebug);
+    wait(DISP_SLOW);
+
+/*       
+///////////////////////////////////////////////////////////////////////////////
+// testing ad9851 routines
+    lcdt.cls();                             //init the LCD
+    lcdt.locate(0,0);                       //column(0-15), row(0-1)
+    lcdt.printf("Testing");                 //print Testing on LCD
+    lcdt.locate(0,1);                       //column(0-15), row(0-1)
+    lcdt.printf("AD9851...");               //print item on LCD
+    wait(DISP_SLOW);
+    double Fdata;
+    Fdata = dds60.GetBaseValue();    
+    pc.printf("----------\nTesting AD9851 routines\nBase Freq: %.3f\n", Fdata);
+    Fdata = dds60.GetIfValue();    
+    pc.printf("IF Freq:   %.3f\n", Fdata);
+    unsigned int UIdata;
+    UIdata = dds60.GetFD32Value();    
+    pc.printf("32 SDO:    0x%08x\n", UIdata);
+    char Cdata;
+    Cdata = dds60.GetFortyValue();    
+    pc.printf("5th byte:  0x%02x\n", Cdata);
+    pc.printf("40 bit wd: 0x%02x%08x\n", Cdata, UIdata);
+    dds60.AD9851Enable();
+    Cdata = dds60.GetFortyValue();    
+    pc.printf("5th byte:  0x%02x\n", Cdata);
+    dds60.AD9851Disable();
+    Cdata = dds60.GetFortyValue();    
+    pc.printf("5th byte:  0x%02x\n", Cdata);
+    dds60.CalcNewValue();
+    UIdata = dds60.GetFD32Value();    
+    Cdata = dds60.GetFortyValue();    
+    pc.printf("40 bit wd: 0x%02x%08x\n", Cdata, UIdata);
+    pc.printf("----------\n");
+    dds60.AD9851Enable();
+    bool ErFlag;
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  1 error!!\n");
+    dds60.SetBaseValue(7320000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  2 error!!\n");
+    dds60.SetIfValue(1620000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  3 error!!\n");
+    dds60.SetM6Value('0');
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  4 error!!\n");
+    dds60.SetBaseValue(30320000.0);
+    ErFlag = dds60.CalcNewValue();
+    if(ErFlag == true) pc.printf("  5a error!!\n");
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  5 error!!\n");
+    
+    dds60.SetM6Value('1');
+    ErFlag = dds60.CalcNewValue();
+    if(ErFlag == true) pc.printf("  6a error!!\n");
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  6 error!!\n");
+    dds60.SetBaseValue(30320000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  7 error!!\n");
+    
+    dds60.SetM6Value('A');
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  8 error!!\n");
+    dds60.SetBaseValue(30320000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf("  9 error!!\n");
+    
+    dds60.SetBaseValue(180000000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 10 error!!\n");
+    
+    dds60.SetBaseValue(27000000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 11 error!!\n");
+    
+    dds60.SetBaseValue(127000000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 12 error!!\n");
+    
+    dds60.SetBaseValue(10000000.0);
+    dds60.SetIfValue(0.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 13 error!!\n");
+    
+    dds60.SetBaseValue(123456.789);
+    dds60.SetIfValue(0.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 14 error!!\n");
+    
+    dds60.SetBaseValue(29545000.0);
+    dds60.SetIfValue(455000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 15 error!!\n");
+    
+    dds60.SetBaseValue(29544999.999);
+    dds60.SetIfValue(455000.0);
+    dds60.CalcNewValue();
+    ErFlag = dds60.GetErrFlagValue();
+    if(ErFlag == true) pc.printf(" 16 error!!\n");
+    
+    pc.printf("----------\n");
+*/    
+///////////////////////////////////////////////////////////////////////////////    
+//    pc.printf("----------\nTesting MOSERIAL routines\n");
+//    int c = 'A';
+//    lcdt.cls();                             //init the LCD
+//    lcdt.locate(0,0);                       //column(0-15), row(0-1)
+//    lcdt.printf("Testing");                 //print Testing on LCD
+//    lcdt.locate(0,1);                       //column(0-15), row(0-1)
+//    lcdt.printf("MODSERIAL...");            //print item on LCD
+    
+    // Ensure the baud rate for the PC "USB" serial is much
+    // higher than "uart" baud rate below.
+//    pc.baud(PC_BAUD);
+    
+    // Use a deliberatly slow baud to fill up the TX buffer
+//    uart.baud(1200);
+    
+//    uart.attach(&txCallback, MODSERIAL::TxIrq);
+//    uart.attach(&rxCallback, MODSERIAL::RxIrq);
+//    uart.attach(&txEmpty,    MODSERIAL::TxEmpty);
+    
+//    pc.attach(&rxCallbackpc, MODSERIAL::RxIrq);
+    pc.attach(&Rx_interrupt, Serial::RxIrq);
+
+    
+//    led1 = 1; // Show start of sending with LED1.
+    
+//    for (int loop = 0; loop < 512; loop++) {
+//        uart.printf("%c", c);        
+//        c++;
+//        if (c > 'Z') c = 'A';
+//    }
+    
+    
+    // End program. Flash LED4. Notice how LED 2 and 3 continue
+    // to flash for a short period while the interrupt system 
+    // continues to send the characters left in the TX buffer.
+    
+    ErFlag = dds60.CalcNewValue();          //init DDS-60
+
+    lcdt.cls();                             //init the LCD
+    lcdt.locate(0,0);                       //column(0-15), row(0-1)
+    lcdt.printf("DDS-60 %d", revision);     //print revision on LCD
+        
+    pcClrLineBuf();
+    mainMenu();
+//    int loop = 0;
+    Fcmd = 0;
+    Sequence = 0;
+    Tic = 0;
+    while (true) {
+        wait(0.05);
+        if(Led1Up == true) {
+            Led1Pwm = Led1Pwm + 0.005;
+            led1 = Led1Pwm;
+            if(Led1Pwm >= 0.20) {
+                Led1Up = false;
+            }
+        } else {
+            Led1Pwm = Led1Pwm - 0.005;
+            led1 = Led1Pwm;
+            if(Led1Pwm <= 0.01) {
+                Led1Up = true;
+            }
+        }
+//        led1 = !led1;
+
+        pcRx();
+        
+        Tic = Tic++;
+        if(Tic >= 40) {
+            Tic = 0;
+            UpdLCD();           //update LCD Values
+            Sequence = Sequence++;
+            if(Sequence >= 6) Sequence = 0;
+        }
+
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbedADC/adc.cpp	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,439 @@
+/* mbed Library - ADC
+ * Copyright (c) 2010, sblandford
+ * released under MIT license http://mbed.org/licence/mit
+ */
+#include "mbed.h"
+#include "adc.h"
+
+
+ADC *ADC::instance;
+
+ADC::ADC(int sample_rate, int cclk_div)
+    {
+
+    int i, adc_clk_freq, pclk, clock_div, max_div=1;
+
+    //Work out CCLK
+    adc_clk_freq=CLKS_PER_SAMPLE*sample_rate;
+    int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
+    int n = (LPC_SC->PLL0CFG >> 16) + 1;
+    int cclkdiv = LPC_SC->CCLKCFG + 1;
+    int Fcco = (2 * m * XTAL_FREQ) / n;
+    int cclk = Fcco / cclkdiv;
+
+    //Power up the ADC        
+    LPC_SC->PCONP |= (1 << 12);
+    //Set clock at cclk / 1.
+    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);    
+    switch (cclk_div) {
+        case 1:
+            LPC_SC->PCLKSEL0 |= 0x1 << 24;
+            break;
+        case 2:
+            LPC_SC->PCLKSEL0 |= 0x2 << 24;
+            break;
+        case 4:
+            LPC_SC->PCLKSEL0 |= 0x0 << 24;
+            break;
+        case 8:
+            LPC_SC->PCLKSEL0 |= 0x3 << 24;
+            break;
+        default:
+            fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
+                cclk_div);
+            fprintf(stderr, "Defaulting to 1.\n");
+            LPC_SC->PCLKSEL0 |= 0x1 << 24;
+            break;
+    }
+    pclk = cclk / cclk_div;
+    clock_div=pclk / adc_clk_freq;
+
+    if (clock_div > 0xFF) {
+        fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n",
+            clock_div);
+        clock_div=0xFF;
+    }
+    if (clock_div == 0) {
+        fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
+        clock_div=1;
+    }
+
+    _adc_clk_freq=pclk / clock_div;
+    if (_adc_clk_freq > MAX_ADC_CLOCK) {
+        fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n",
+            _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
+        while ((pclk / max_div) > MAX_ADC_CLOCK) max_div++;
+        fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
+    }
+
+    LPC_ADC->ADCR =
+        ((clock_div - 1 ) << 8 ) |    //Clkdiv
+        ( 1 << 21 );                  //A/D operational
+
+    //Default no channels enabled
+    LPC_ADC->ADCR &= ~0xFF;
+    //Default NULL global custom isr
+    _adc_g_isr = NULL;
+    //Initialize arrays
+    for (i=7; i>=0; i--) {
+        _adc_data[i] = 0;
+        _adc_isr[i] = NULL;
+    }
+
+
+    //* Attach IRQ
+    instance = this;
+    NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
+
+    //Disable global interrupt
+    LPC_ADC->ADINTEN &= ~0x100;
+
+};
+
+void ADC::_adcisr(void)
+{
+    instance->adcisr();
+}
+
+
+void ADC::adcisr(void)  
+{
+    uint32_t stat;
+    int chan;
+
+    // Read status
+    stat = LPC_ADC->ADSTAT;
+    //Scan channels for over-run or done and update array
+    if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
+    if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
+    if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
+    if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
+    if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
+    if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
+    if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
+    if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
+
+    // Channel that triggered interrupt
+    chan = (LPC_ADC->ADGDR >> 24) & 0x07;
+    //User defined interrupt handlers
+    if (_adc_isr[chan] != NULL)
+        _adc_isr[chan](_adc_data[chan]);
+    if (_adc_g_isr != NULL)
+        _adc_g_isr(chan, _adc_data[chan]); 
+    return;
+}
+
+int ADC::_pin_to_channel(PinName pin) {
+    int chan;
+    switch (pin) {
+        case p15://=p0.23 of LPC1768
+        default:
+            chan=0;
+            break;
+        case p16://=p0.24 of LPC1768
+            chan=1;
+            break;
+        case p17://=p0.25 of LPC1768
+            chan=2;
+            break;
+        case p18://=p0.26 of LPC1768
+            chan=3;
+            break;
+        case p19://=p1.30 of LPC1768
+            chan=4;
+            break;
+        case p20://=p1.31 of LPC1768
+            chan=5;
+            break;
+    }
+    return(chan);
+}
+
+PinName ADC::channel_to_pin(int chan) {
+    const PinName pin[8]={p15, p16, p17, p18, p19, p20, p15, p15};
+    
+    if ((chan < 0) || (chan > 5))
+        fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
+    return(pin[chan & 0x07]);
+} 
+
+
+int ADC::channel_to_pin_number(int chan) {
+    const int pin[8]={15, 16, 17, 18, 19, 20, 0, 0};
+    
+    if ((chan < 0) || (chan > 5))
+        fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
+    return(pin[chan & 0x07]);
+} 
+
+
+uint32_t ADC::_data_of_pin(PinName pin) {
+    //If in burst mode and at least one interrupt enabled then
+    //take all values from _adc_data
+    if (burst() && (LPC_ADC->ADINTEN & 0x3F)) {
+        return(_adc_data[_pin_to_channel(pin)]);
+    } else {
+        //Return current register value or last value from interrupt
+        switch (pin) {
+            case p15://=p0.23 of LPC1768
+            default:
+                return(LPC_ADC->ADINTEN & 0x01?_adc_data[0]:LPC_ADC->ADDR0);
+            case p16://=p0.24 of LPC1768
+                return(LPC_ADC->ADINTEN & 0x02?_adc_data[1]:LPC_ADC->ADDR1);
+            case p17://=p0.25 of LPC1768
+                return(LPC_ADC->ADINTEN & 0x04?_adc_data[2]:LPC_ADC->ADDR2);
+            case p18://=p0.26 of LPC1768:
+                return(LPC_ADC->ADINTEN & 0x08?_adc_data[3]:LPC_ADC->ADDR3);
+            case p19://=p1.30 of LPC1768
+                return(LPC_ADC->ADINTEN & 0x10?_adc_data[4]:LPC_ADC->ADDR4);
+            case p20://=p1.31 of LPC1768
+                return(LPC_ADC->ADINTEN & 0x20?_adc_data[5]:LPC_ADC->ADDR5);
+        }
+    }
+}
+
+//Enable or disable an ADC pin
+void ADC::setup(PinName pin, int state) {
+    int chan;    
+    chan=_pin_to_channel(pin);
+    if ((state & 1) == 1) {
+        switch(pin) {
+            case p15://=p0.23 of LPC1768
+            default:
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
+                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
+                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
+                break;
+            case p16://=p0.24 of LPC1768
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
+                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
+                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
+                break;
+            case p17://=p0.25 of LPC1768
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
+                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
+                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
+                break;
+            case p18://=p0.26 of LPC1768:
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
+                LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
+                LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
+                break;
+            case p19://=p1.30 of LPC1768
+                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
+                LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
+                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
+                LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
+                break;
+            case p20://=p1.31 of LPC1768
+                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
+                LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
+                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
+                LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
+               break;
+        }
+        //Only one channel can be selected at a time if not in burst mode
+        if (!burst()) LPC_ADC->ADCR &= ~0xFF;
+        //Select channel
+        LPC_ADC->ADCR |= (1 << chan);
+    }
+    else {
+        switch(pin) {
+            case p15://=p0.23 of LPC1768
+            default:
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
+                break;
+            case p16://=p0.24 of LPC1768
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
+                break;
+            case p17://=p0.25 of LPC1768
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
+                break;
+            case p18://=p0.26 of LPC1768:
+                LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
+                LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
+                break;
+            case p19://=p1.30 of LPC1768
+                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
+                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
+                break;
+            case p20://=p1.31 of LPC1768
+                LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
+                LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
+                break;
+        }
+        LPC_ADC->ADCR &= ~(1 << chan);
+    }
+}
+//Return channel enabled/disabled state
+int ADC::setup(PinName pin) {
+    int chan;
+    
+    chan = _pin_to_channel(pin);
+    return((LPC_ADC->ADCR & (1 << chan)) >> chan);
+}
+
+//Select channel already setup
+void ADC::select(PinName pin) {
+    int chan;
+    
+    //Only one channel can be selected at a time if not in burst mode
+    if (!burst()) LPC_ADC->ADCR &= ~0xFF;
+    //Select channel
+    chan = _pin_to_channel(pin);
+    LPC_ADC->ADCR |= (1 << chan);
+}
+
+//Enable or disable burst mode
+void ADC::burst(int state) {
+    if ((state & 1) == 1) {
+        if (startmode(0) != 0)
+            fprintf(stderr, "Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
+        LPC_ADC->ADCR |= (1 << 16);
+    }
+    else 
+        LPC_ADC->ADCR &= ~(1 << 16);
+}
+//Return burst mode state
+int  ADC::burst(void) {
+    return((LPC_ADC->ADCR & (1 << 16)) >> 16);
+}
+
+//Set startmode and edge
+void ADC::startmode(int mode, int edge) {
+    int lpc_adc_temp;
+    
+    //Reset start mode and edge bit, 
+    lpc_adc_temp = LPC_ADC->ADCR & ~(0x0F << 24);
+    //Write with new values
+    lpc_adc_temp |= ((mode & 7) << 24) | ((edge & 1) << 27);
+    LPC_ADC->ADCR = lpc_adc_temp;
+}
+
+//Return startmode state according to mode_edge=0: mode and mode_edge=1: edge
+int ADC::startmode(int mode_edge){
+    switch (mode_edge) {
+        case 0:
+        default:
+            return((LPC_ADC->ADCR >> 24) & 0x07);
+        case 1:
+            return((LPC_ADC->ADCR >> 27) & 0x01);
+    }
+}
+
+//Start ADC conversion
+void ADC::start(void) {
+    startmode(1,0);
+}
+
+
+//Set interrupt enable/disable for pin to state
+void ADC::interrupt_state(PinName pin, int state) {
+    int chan;
+    
+    chan = _pin_to_channel(pin);
+    if (state == 1) {
+        LPC_ADC->ADINTEN &= ~0x100;
+        LPC_ADC->ADINTEN |= 1 << chan;
+        /* Enable the ADC Interrupt */
+        NVIC_EnableIRQ(ADC_IRQn);
+    } else {
+        LPC_ADC->ADINTEN &= ~( 1 << chan );
+        //Disable interrrupt if no active pins left
+        if ((LPC_ADC->ADINTEN & 0xFF) == 0)
+            NVIC_DisableIRQ(ADC_IRQn);
+    }
+}
+
+//Return enable/disable state of interrupt for pin
+int ADC::interrupt_state(PinName pin) {
+    int chan;
+        
+    chan = _pin_to_channel(pin);
+    return((LPC_ADC->ADINTEN >> chan) & 0x01);
+}
+
+
+//Attach custom interrupt handler replacing default
+void ADC::attach(void(*fptr)(void)) {
+    //* Attach IRQ
+    NVIC_SetVector(ADC_IRQn, (uint32_t)fptr);
+}
+
+//Restore default interrupt handler
+void ADC::detach(void) {
+    //* Attach IRQ
+    instance = this;
+    NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
+}
+
+
+//Append interrupt handler for pin to function isr
+void ADC::append(PinName pin, void(*fptr)(uint32_t value)) {
+    int chan;
+        
+    chan = _pin_to_channel(pin);
+    _adc_isr[chan] = fptr;
+}
+
+//Append interrupt handler for pin to function isr
+void ADC::unappend(PinName pin) {
+    int chan;
+        
+    chan = _pin_to_channel(pin);
+    _adc_isr[chan] = NULL;
+}
+
+//Unappend global interrupt handler to function isr
+void ADC::append(void(*fptr)(int chan, uint32_t value)) {
+    _adc_g_isr = fptr;
+}
+
+//Detach global interrupt handler to function isr
+void ADC::unappend() {
+    _adc_g_isr = NULL;
+}
+
+//Set ADC offset
+void offset(int offset) {
+    LPC_ADC->ADTRM &= ~(0x07 << 4);
+    LPC_ADC->ADTRM |= (offset & 0x07) << 4;
+}
+
+//Return current ADC offset
+int offset(void) {
+    return((LPC_ADC->ADTRM >> 4) & 0x07);
+}
+
+//Return value of ADC on pin
+int ADC::read(PinName pin) {
+    //Reset DONE and OVERRUN flags of interrupt handled ADC data
+    _adc_data[_pin_to_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
+    //Return value
+    return((_data_of_pin(pin) >> 4) & 0xFFF);
+}
+
+//Return DONE flag of ADC on pin
+int ADC::done(PinName pin) {
+    return((_data_of_pin(pin) >> 31) & 0x01);
+}
+
+//Return OVERRUN flag of ADC on pin
+int ADC::overrun(PinName pin) {
+    return((_data_of_pin(pin) >> 30) & 0x01);
+}
+
+int ADC::actual_adc_clock(void) {
+    return(_adc_clk_freq);
+}
+
+int ADC::actual_sample_rate(void) {
+    return(_adc_clk_freq / CLKS_PER_SAMPLE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbedADC/adc.h	Wed Apr 04 18:14:54 2012 +0000
@@ -0,0 +1,131 @@
+/* mbed Library - ADC
+ * Copyright (c) 2010, sblandford
+ * released under MIT license http://mbed.org/licence/mit
+ */
+
+#ifndef MBED_ADC_H
+#define MBED_ADC_H
+ 
+#include "mbed.h"
+#define XTAL_FREQ       12000000
+#define MAX_ADC_CLOCK   13000000
+#define CLKS_PER_SAMPLE 64
+
+class ADC {
+public:
+
+    //Initialize ADC with ADC maximum sample rate of
+    //sample_rate and system clock divider of cclk_div
+    //Maximum recommened sample rate is 184000
+    ADC(int sample_rate, int cclk_div);
+
+    //Enable/disable ADC on pin according to state
+    //and also select/de-select for next conversion
+    void setup(PinName pin, int state);
+
+    //Return enabled/disabled state of ADC on pin
+    int setup(PinName pin);
+
+    //Enable/disable burst mode according to state
+    void burst(int state);
+
+    //Select channel already setup
+    void select(PinName pin);
+
+    //Return burst mode enabled/disabled
+    int burst(void);
+
+    /*Set start condition and edge according to mode:
+    0 - No start (this value should be used when clearing PDN to 0).
+    1 - Start conversion now.
+    2 - Start conversion when the edge selected by bit 27 occurs on the P2.10 / EINT0 / NMI pin.
+    3 - Start conversion when the edge selected by bit 27 occurs on the P1.27 / CLKOUT /
+        USB_OVRCRn / CAP0.1 pin.
+    4 - Start conversion when the edge selected by bit 27 occurs on MAT0.1. Note that this does
+        not require that the MAT0.1 function appear on a device pin.
+    5 - Start conversion when the edge selected by bit 27 occurs on MAT0.3. Note that it is not
+        possible to cause the MAT0.3 function to appear on a device pin.
+    6 - Start conversion when the edge selected by bit 27 occurs on MAT1.0. Note that this does
+        not require that the MAT1.0 function appear on a device pin.
+    7 - Start conversion when the edge selected by bit 27 occurs on MAT1.1. Note that this does
+        not require that the MAT1.1 function appear on a device pin.
+    When mode >= 2, conversion is triggered by edge:
+    0 - Rising edge
+    1 - Falling edge
+    */
+    void startmode(int mode, int edge);
+    
+    //Return startmode state according to mode_edge=0: mode and mode_edge=1: edge
+    int startmode(int mode_edge);
+    
+    //Start ADC conversion
+    void start(void);
+
+    //Set interrupt enable/disable for pin to state
+    void interrupt_state(PinName pin, int state);
+    
+    //Return enable/disable state of interrupt for pin
+    int interrupt_state(PinName pin);
+
+    //Attach custom interrupt handler replacing default
+    void attach(void(*fptr)(void));
+
+    //Restore default interrupt handler
+    void detach(void);
+
+    //Append custom interrupt handler for pin
+    void append(PinName pin, void(*fptr)(uint32_t value));
+
+    //Unappend custom interrupt handler for pin
+    void unappend(PinName pin);
+
+    //Append custom global interrupt handler
+    void append(void(*fptr)(int chan, uint32_t value));
+
+    //Unappend custom global interrupt handler
+    void unappend(void);
+
+    //Set ADC offset to a value 0-7
+    void offset(int offset);
+    
+    //Return current ADC offset
+    int offset(void);
+
+    //Return value of ADC on pin
+    int read(PinName pin);
+
+    //Return DONE flag of ADC on pin
+    int done(PinName pin);
+    
+    //Return OVERRUN flag of ADC on pin
+    int overrun(PinName pin);
+
+    //Return actual ADC clock
+    int actual_adc_clock(void);
+    
+    //Return actual maximum sample rate
+    int actual_sample_rate(void);
+
+    //Return pin ID of ADC channel
+    PinName channel_to_pin(int chan);
+
+    //Return pin number of ADC channel
+    int channel_to_pin_number(int chan);
+
+
+private:
+    int _pin_to_channel(PinName pin);
+    uint32_t _data_of_pin(PinName pin);
+
+    int _adc_clk_freq;
+    void adcisr(void);
+    static void _adcisr(void);
+    static ADC *instance;
+    
+    uint32_t _adc_data[8];
+    void(*_adc_isr[8])(uint32_t value);
+    void(*_adc_g_isr)(int chan, uint32_t value);
+    void(*_adc_m_isr)(void);
+};
+
+#endif
\ No newline at end of file