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
Revision 0:1ed24aaf786d, committed 2012-04-04
- Comitter:
- loopsva
- Date:
- Wed Apr 04 18:14:54 2012 +0000
- Commit message:
- 050511
Changed in this revision
--- /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