This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PGA460PSM-EVM: Interfacing with TivaC Launchpad

Part Number: PGA460-Q1
Other Parts Discussed in Thread: PGA460PSM-EVM, PGA460, ENERGIA, , MSP-EXP430F5529LP, BOOSTXL-PGA460

Hello,

I have "PGA460PSM-EVM" ultra-sonic sensor

I want to run it on TivaC Launchpad,

it gives me strange results,

No Objects

or Contatnt Number [3.95 m]

I tried to connect using this settimgs:

UART connection

115200 baudrate

number of objects: i tried all options 1 >> 8

address: 0

all other options left default number

here .. Link to my Code modified from the original Library :

Any Help?

  • Part Number: PGA460-Q1

    Hi,

    I am trying to run the PGA460 EVM on arduino using UART Mode,

    Using this code:

    #include <SoftwareSerial.h>
    
    SoftwareSerial mySerial(8, 9); // RX, TX
    
    //note: bare bones raw UART demo used to send a burst/listen command to PGA460
    byte syncByte = 0x55;
    
    //cmd 0 - p1 burst listen
    byte buf0[4]   = {syncByte, 0x00, 0x01, 0xFE};
    //cmd 1 - p2 burst listen
    byte buf1[4]   = {syncByte, 0x01, 0x01, 0xFD};
    //cmd 5 - ultrasonic measurement (assume UART_ADDR=0)
    byte buf5[4]   = {syncByte, 0x05, 0xFA};
    //cmd 10 - register write decple to time of 4.096ms
    byte buf10[5]  = {syncByte, 0x0A, 0x26, 0x00, 0xCF};
    //cmd 17 - broadcast p1 burst listen
    byte buf17[4]  = {syncByte, 0x11, 0x01, 0xED};
    //cmd 19 - broadcast p1 listen only
    byte buf19[4]  = {syncByte, 0x13, 0x01, 0xEB};
    //cmd 25 - broadcast bulk threshold write
    byte buf25[35] = {syncByte, 0x19, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x84, 0x21, 0x08, 0x42, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x84, 0x21, 0x08, 0x42, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x7C};
    
    const int ledPin = 13;       // the number of the LED pin
    int buttonState  = 0;        // variable for reading the pushbutton status
    
    void setup()
    {
      pinMode(ledPin, OUTPUT);
      delay(10);
    
      // put your setup code here, to run once:
      Serial.begin(19200);    // initialize serial channel
      mySerial.begin(19200);  // initialize PGA460 UART serial channel
      delay(100);
    
      //assume UART_ADDR=0
      //bulk threshold write mid-code values to clear THR_CRC_ERR
      mySerial.write(buf25, sizeof(buf25));
      delay(100);
    
      // [TODO] set p1 rec length to 4.096ms
      // set UART_ADDR=0's time decouple to 4.096ms
      //mySerial.write(buf10, sizeof(buf10));
      //delay(100);
    }
    
    
    void loop()
    {
      // broadcast p1 burst+listen (non-dependent on UART_ADDR)
      mySerial.write(buf17, sizeof(buf17));
    
      delay(10);
    
      //[TODO] print ultrasonic measurement results on terminal
      // read back ultrasonic meas results from UART_ADDR=0
      mySerial.write(buf5, sizeof(buf5));
    
      if (mySerial.available())
      {
        byte reading = mySerial.read();
        if (reading == 255)
        {
          Serial.println();
        }
        else
          Serial.print(reading,HEX);
      }
      // toggle red LED
      digitalWrite(ledPin, !(digitalRead(ledPin)));   // turn the LED on (HIGH is the voltage level)
    
      // repeat loop every second
      delay (150);
    }

    All i get is "BFFB" for about 20 times then the sensor goes to idle [output is FF]

    Any Help ?

  • Tekomoro Carkyo,

    The code snippet you are referring to has not been officially tested/released, so I advise against using it for your development. Please refer to the PGA460 Energia Library and Code Example and PGA460 Software Development Guide for guidance on programming your microcontroller. The Energia library can be ported to Arduino.

  • Thank You,

    I tried implementing the function i need from the library in my Arduino code [which is attached]

    it gets stuck in line 806 giving me this error "Error reading measurement results...",
    My CODE:




    #pragma region globals // Pin mapping of BOOSTXL-PGA460 to LaunchPad by pin name #define DECPL_A 2 #define RXD_LP 3 #define TXD_LP 4 #define DECPL_D 5 #define TEST_A 6 #define TCI_CLK 7 #define TEST_D 8 #define MEM_SOMI 9 #define MEM_SIMO 10 #define TCI_RX 14 #define TCI_TX 15 #define COM_SEL 17 #define COM_PD 18 #define SPI_CS 33 #define SCLK_CLK 34 #define MEM_HOLD 36 #define MEM_CS 37 #define DS1_LED 38 #define F_DIAG_LED 39 #define V_DIAG_LED 40 // Serial read timeout in milliseconds #define MAX_MILLIS_TO_WAIT 250 // Define UART commands by name // Single Address byte P1BL = 0x00; byte P2BL = 0x01; byte P1LO = 0x02; byte P2LO = 0x03; byte TNLM = 0x04; byte UMR = 0x05; byte TNLR = 0x06; byte TEDD = 0x07; byte SD = 0x08; byte SRR = 0x09; byte SRW = 0x0A; byte EEBR = 0x0B; byte EEBW = 0x0C; byte TVGBR = 0x0D; byte TVGBW = 0x0E; byte THRBR = 0x0F; byte THRBW = 0x10; //Broadcast byte BC_P1BL = 0x11; byte BC_P2BL = 0x12; byte BC_P1LO = 0x13; byte BC_P2LO = 0x14; byte BC_TNLM = 0x15; byte BC_RW = 0x16; byte BC_EEBW = 0x17; byte BC_TVGBW = 0x18; byte BC_THRBW = 0x19; //CMDs 26-31 are reserved // List user registers by name with default settings from TI factory byte USER_DATA1 = 0x00; byte USER_DATA2 = 0x00; byte USER_DATA3 = 0x00; byte USER_DATA4 = 0x00; byte USER_DATA5 = 0x00; byte USER_DATA6 = 0x00; byte USER_DATA7 = 0x00; byte USER_DATA8 = 0x00; byte USER_DATA9 = 0x00; byte USER_DATA10 = 0x00; byte USER_DATA11 = 0x00; byte USER_DATA12 = 0x00; byte USER_DATA13 = 0x00; byte USER_DATA14 = 0x00; byte USER_DATA15 = 0x00; byte USER_DATA16 = 0x00; byte USER_DATA17 = 0x00; byte USER_DATA18 = 0x00; byte USER_DATA19 = 0x00; byte USER_DATA20 = 0x00; byte TVGAIN0 = 0xAF; byte TVGAIN1 = 0xFF; byte TVGAIN2 = 0xFF; byte TVGAIN3 = 0x2D; byte TVGAIN4 = 0x68; byte TVGAIN5 = 0x36; byte TVGAIN6 = 0xFC; byte INIT_GAIN = 0xC0; byte FREQUENCY = 0x8C; byte DEADTIME = 0x00; byte PULSE_P1 = 0x01; byte PULSE_P2 = 0x12; byte CURR_LIM_P1 = 0x47; byte CURR_LIM_P2 = 0xFF; byte REC_LENGTH = 0x1C; byte FREQ_DIAG = 0x00; byte SAT_FDIAG_TH = 0xEE; byte FVOLT_DEC = 0x7C; byte DECPL_TEMP = 0x0A; byte DSP_SCALE = 0x00; byte TEMP_TRIM = 0x00; byte P1_GAIN_CTRL = 0x00; byte P2_GAIN_CTRL = 0x00; byte EE_CRC = 0xFF; byte EE_CNTRL = 0x00; byte P1_THR_0 = 0x88; byte P1_THR_1 = 0x88; byte P1_THR_2 = 0x88; byte P1_THR_3 = 0x88; byte P1_THR_4 = 0x88; byte P1_THR_5 = 0x88; byte P1_THR_6 = 0x84; byte P1_THR_7 = 0x21; byte P1_THR_8 = 0x08; byte P1_THR_9 = 0x42; byte P1_THR_10 = 0x10; byte P1_THR_11 = 0x80; byte P1_THR_12 = 0x80; byte P1_THR_13 = 0x80; byte P1_THR_14 = 0x80; byte P1_THR_15 = 0x80; byte P2_THR_0 = 0x88; byte P2_THR_1 = 0x88; byte P2_THR_2 = 0x88; byte P2_THR_3 = 0x88; byte P2_THR_4 = 0x88; byte P2_THR_5 = 0x88; byte P2_THR_6 = 0x84; byte P2_THR_7 = 0x21; byte P2_THR_8 = 0x08; byte P2_THR_9 = 0x42; byte P2_THR_10 = 0x10; byte P2_THR_11 = 0x80; byte P2_THR_12 = 0x80; byte P2_THR_13 = 0x80; byte P2_THR_14 = 0x80; byte P2_THR_15 = 0x80; // Miscellaneous variables; (+) indicates OWU transmitted byte offset byte checksum = 0x00; // UART checksum value byte ChecksumInput[44]; // data byte array for checksum calculator byte ultraMeasResult[34+3]; // data byte array for cmd5 and tciB+L return byte diagMeasResult[5+3]; // data byte array for cmd8 and index1 return byte tempNoiseMeasResult[4+3]; // data byte array for cmd6 and index0&1 return byte echoDataDump[130+3]; // data byte array for cmd7 and index12 return byte tempOrNoise = 0; // data byte to determine if temp or noise measurement is to be performed byte comm = 0; // indicates UART (0), TCI (1), OWU (2) communication mode unsigned long starttime; // used for function time out byte bulkThr[34+3]; // data byte array for bulk threhsold commands //UART & OWU exclusive variables byte syncByte = 0x55; // data byte for Sync field set UART baud rate of PGA460 byte regAddr = 0x00; // data byte for Register Address byte regData = 0x00; // data byte for Register Data byte uartAddr = 0; // PGA460 UART device address (0-7). '0' is factory default address byte numObj = 1; // number of objects to detect signed int owuShift = 0; // accoutns for OWU receiver buffer offset for capturing master transmitted data - always 0 for standard two-wire UART #pragma endregion globals // Configuration variables byte commMode = 0; // Communication mode: 0=UART, 1=TCI, 2=OneWireUART byte fixedThr = 1; // set P1 and P2 thresholds to 0=%25, 1=50%, or 2=75% of max; initial minDistLim (i.e. 20cm) ignored byte xdcr = 1; // set PGA460 to recommended settings for 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R byte agrTVG = 2; // set TVG's analog front end gain range to 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB byte fixedTVG = 1; // set fixed TVG level at 0=%25, 1=50%, or 1=75% of max byte runDiag = 0; // run system diagnostics and temp/noise level before looping burst+listen command byte edd = 0; // echo data dump of preset 1, 2, or neither byte burn = 0; // trigger EE_CNTRL to burn and program user EEPROM memory byte cdMultiplier = 1; // multiplier for command cycle delay byte numOfObj = 5; // number of object to detect set to 1-8 byte uartAddrUpdate = 0; // PGA460 UART address to interface to; default is 0, possible address 0-7 bool objectDetected = false; // object detected flag to break burst+listen cycle when true bool demoMode = false; // only true when running UART/OWU multi device demo mode bool alwaysLong = false; // always run preset 2, regardless of preset 1 result (hard-coded only) double minDistLim = 0.1; // minimum distance as limited by ringing decay of single transducer and threshold masking uint16_t commandDelay = 0; // Delay between each P1 and Preset 2 command uint32_t baudRate = 9600; // UART baud rate: 9600, 19200, 38400, 57600, 74800, 115200 // Result variables double distance = 0; // one-way object distance in meters double width = 0; // object width in microseconds double peak = 0; // object peak in 8-bit double diagnostics = 0; // diagnostic selector byte echoDataDumpElement = 0; // echo data dump element 0 to 127 String interruptString = ""; // a string to hold incoming data boolean stringComplete = false; // whether the string is complete #include <SoftwareSerial.h> SoftwareSerial mySerial(8, 9); // RX, TX byte calcChecksum(byte cmd) { int checksumLoops = 0; cmd = cmd & 0x001F; // zero-mask command address of cmd to select correct switch-case statement switch(cmd) { case 0 : //P1BL case 1 : //P2BL case 2 : //P1LO case 3 : //P2LO case 17 : //BC_P1BL case 18 : //BC_P2BL case 19 : //BC_P1LO case 20 : //BC_P2LO ChecksumInput[0] = cmd; ChecksumInput[1] = numObj; checksumLoops = 2; break; case 4 : //TNLM case 21 : //TNLM ChecksumInput[0] = cmd; ChecksumInput[1] = tempOrNoise; checksumLoops = 2; break; case 5 : //UMR case 6 : //TNLR case 7 : //TEDD case 8 : //SD case 11 : //EEBR case 13 : //TVGBR case 15 : //THRBR ChecksumInput[0] = cmd; checksumLoops = 1; break; case 9 : //RR ChecksumInput[0] = cmd; ChecksumInput[1] = regAddr; checksumLoops = 2; break; case 10 : //RW case 22 : //BC_RW ChecksumInput[0] = cmd; ChecksumInput[1] = regAddr; ChecksumInput[2] = regData; checksumLoops = 3; break; case 14 : //TVGBW case 24 : //BC_TVGBW ChecksumInput[0] = cmd; ChecksumInput[1] = TVGAIN0; ChecksumInput[2] = TVGAIN1; ChecksumInput[3] = TVGAIN2; ChecksumInput[4] = TVGAIN3; ChecksumInput[5] = TVGAIN4; ChecksumInput[6] = TVGAIN5; ChecksumInput[7] = TVGAIN6; checksumLoops = 8; break; case 16 : //THRBW case 25 : //BC_THRBW ChecksumInput[0] = cmd; ChecksumInput[1] = P1_THR_0; ChecksumInput[2] = P1_THR_1; ChecksumInput[3] = P1_THR_2; ChecksumInput[4] = P1_THR_3; ChecksumInput[5] = P1_THR_4; ChecksumInput[6] = P1_THR_5; ChecksumInput[7] = P1_THR_6; ChecksumInput[8] = P1_THR_7; ChecksumInput[9] = P1_THR_8; ChecksumInput[10] = P1_THR_9; ChecksumInput[11] = P1_THR_10; ChecksumInput[12] = P1_THR_11; ChecksumInput[13] = P1_THR_12; ChecksumInput[14] = P1_THR_13; ChecksumInput[15] = P1_THR_14; ChecksumInput[16] = P1_THR_15; ChecksumInput[17] = P2_THR_0; ChecksumInput[18] = P2_THR_1; ChecksumInput[19] = P2_THR_2; ChecksumInput[20] = P2_THR_3; ChecksumInput[21] = P2_THR_4; ChecksumInput[22] = P2_THR_5; ChecksumInput[23] = P2_THR_6; ChecksumInput[24] = P2_THR_7; ChecksumInput[25] = P2_THR_8; ChecksumInput[26] = P2_THR_9; ChecksumInput[27] = P2_THR_10; ChecksumInput[28] = P2_THR_11; ChecksumInput[29] = P2_THR_12; ChecksumInput[30] = P2_THR_13; ChecksumInput[31] = P2_THR_14; ChecksumInput[32] = P2_THR_15; checksumLoops = 33; break; case 12 : //EEBW case 23 : //BC_EEBW ChecksumInput[0] = cmd; ChecksumInput[1] = USER_DATA1; ChecksumInput[2] = USER_DATA2; ChecksumInput[3] = USER_DATA3; ChecksumInput[4] = USER_DATA4; ChecksumInput[5] = USER_DATA5; ChecksumInput[6] = USER_DATA6; ChecksumInput[7] = USER_DATA7; ChecksumInput[8] = USER_DATA8; ChecksumInput[9] = USER_DATA9; ChecksumInput[10] = USER_DATA10; ChecksumInput[11] = USER_DATA11; ChecksumInput[12] = USER_DATA12; ChecksumInput[13] = USER_DATA13; ChecksumInput[14] = USER_DATA14; ChecksumInput[15] = USER_DATA15; ChecksumInput[16] = USER_DATA16; ChecksumInput[17] = USER_DATA17; ChecksumInput[18] = USER_DATA18; ChecksumInput[19] = USER_DATA19; ChecksumInput[20] = USER_DATA20; ChecksumInput[21] = TVGAIN0; ChecksumInput[22] = TVGAIN1; ChecksumInput[23] = TVGAIN2; ChecksumInput[24] = TVGAIN3; ChecksumInput[25] = TVGAIN4; ChecksumInput[26] = TVGAIN5; ChecksumInput[27] = TVGAIN6; ChecksumInput[28] = INIT_GAIN; ChecksumInput[29] = FREQUENCY; ChecksumInput[30] = DEADTIME; ChecksumInput[31] = PULSE_P1; ChecksumInput[32] = PULSE_P2; ChecksumInput[33] = CURR_LIM_P1; ChecksumInput[34] = CURR_LIM_P2; ChecksumInput[35] = REC_LENGTH; ChecksumInput[36] = FREQ_DIAG; ChecksumInput[37] = SAT_FDIAG_TH; ChecksumInput[38] = FVOLT_DEC; ChecksumInput[39] = DECPL_TEMP; ChecksumInput[40] = DSP_SCALE; ChecksumInput[41] = TEMP_TRIM; ChecksumInput[42] = P1_GAIN_CTRL; ChecksumInput[43] = P2_GAIN_CTRL; checksumLoops = 44; break; default: break; } if (ChecksumInput[0]<17) //only re-append command address for non-broadcast commands. { ChecksumInput[0] = ChecksumInput[0] + (uartAddr << 5); } uint16_t carry = 0; for (int i = 0; i < checksumLoops; i++) { if ((ChecksumInput[i] + carry) < carry) { carry = carry + ChecksumInput[i] + 1; } else { carry = carry + ChecksumInput[i]; } if (carry > 0xFF) { carry = carry - 255; } } carry = (~carry & 0x00FF); return carry; } void pga460SerialFlush() { delay(10); mySerial.flush(); while((mySerial.available() > 0))// || (mySerial.read() < 0xFF)) { char temp = mySerial.read(); //mySerial.flush(); } //redundant clear for (int i = 0; i < 10; i++) { while (Serial.available() > 0) { char k = Serial.read(); delay(1); } delay(1); } mySerial.flush(); return; } void initBoostXLPGA460(byte mode, uint32_t baud, byte uartAddrUpdate) { // check for valid UART address if (uartAddrUpdate > 7) { uartAddrUpdate = 0; // default to '0' Serial.println("ERROR - Invalid UART Address!"); } // globally update target PGA460 UART address and commands if (uartAddr != uartAddrUpdate) { // Update commands to account for new UART addr // Single Address P1BL = 0x00 + (uartAddrUpdate << 5); P2BL = 0x01 + (uartAddrUpdate << 5); P1LO = 0x02 + (uartAddrUpdate << 5); P2LO = 0x03 + (uartAddrUpdate << 5); TNLM = 0x04 + (uartAddrUpdate << 5); UMR = 0x05 + (uartAddrUpdate << 5); TNLR = 0x06 + (uartAddrUpdate << 5); TEDD = 0x07 + (uartAddrUpdate << 5); SD = 0x08 + (uartAddrUpdate << 5); SRR = 0x09 + (uartAddrUpdate << 5); SRW = 0x0A + (uartAddrUpdate << 5); EEBR = 0x0B + (uartAddrUpdate << 5); EEBW = 0x0C + (uartAddrUpdate << 5); TVGBR = 0x0D + (uartAddrUpdate << 5); TVGBW = 0x0E + (uartAddrUpdate << 5); THRBR = 0x0F + (uartAddrUpdate << 5); THRBW = 0x10 + (uartAddrUpdate << 5); } uartAddr = uartAddrUpdate; if (mode == 0){ // 0=UART, 1=TCI, 2=OWU, 3=SPI comm = mode; } else{ comm = 99; // invalid communication type } switch (mode){ case 0: // UART Mode Serial.begin(baud); // initialize COM UART serial channel mySerial.begin(baud); // initialize PGA460 UART serial channel mySerial.setTimeout(250); break; default: break; } return; } void ultrasonicCmd(byte cmd, byte numObjUpdate) { numObj = numObjUpdate; // number of objects to detect byte bufCmd[4] = {syncByte, 0xFF, numObj, 0xFF}; // prepare bufCmd with 0xFF placeholders switch (cmd) { // SINGLE ADDRESS case 0: // Send Preset 1 Burst + Listen command { bufCmd[1] = P1BL; bufCmd[3] = calcChecksum(P1BL); break; } case 1: // Send Preset 2 Burst + Listen command { bufCmd[1] = P2BL; bufCmd[3] = calcChecksum(P2BL); break; } case 2: // Send Preset 1 Listen Only command { bufCmd[1] = P1LO; bufCmd[3] = calcChecksum(P1LO); break; } case 3: // Send Preset 2 Listen Only command { bufCmd[1] = P2LO; bufCmd[3] = calcChecksum(P2LO); break; } // BROADCAST case 17: // Send Preset 1 Burst + Listen Broadcast command { bufCmd[1] = BC_P1BL; bufCmd[3] = calcChecksum(BC_P1BL); break; } case 18: // Send Preset 2 Burst + Listen Broadcast command { bufCmd[1] = BC_P2BL; bufCmd[3] = calcChecksum(BC_P2BL); break; } case 19: // Send Preset 1 Listen Only Broadcast command { bufCmd[1] = BC_P1LO; bufCmd[3] = calcChecksum(BC_P1LO); break; } case 20: // Send Preset 2 Listen Only Broadcast command { bufCmd[1] = BC_P2LO; bufCmd[3] = calcChecksum(BC_P2LO); break; } default: return; } if (comm == 0){ // UART or OWU mode mySerial.write(bufCmd, sizeof(bufCmd)); // serial transmit master data to initiate burst and/or listen command } else{ //do nothing } delay(70); // maximum record length is 65ms, so delay with margin return; } bool pullUltrasonicMeasResult(bool busDemo) { if (comm != 1) // USART or OWU mode { pga460SerialFlush(); memset(ultraMeasResult, 0, sizeof(ultraMeasResult)); if (comm == 2) { owuShift = 2; // OWU receive buffer offset to ignore transmitted data } byte buf5[3] = {syncByte, UMR, calcChecksum(UMR)}; if (comm == 0 || comm == 2) // UART or OWU mode { mySerial.write(buf5, sizeof(buf5)); //serial transmit master data to read ultrasonic measurement results } if (comm == 0 || comm == 2) // UART or OWU mode { starttime = millis(); while ( (mySerial.available()<(5+owuShift)) && ((millis() - starttime) < MAX_MILLIS_TO_WAIT) ) { // wait in this loop until we either get +5 bytes of data, or 0.25 seconds have gone by } if((mySerial.available() < (5+owuShift))) { if (busDemo == false) { // the data didn't come in - handle the problem here Serial.println("ERROR - Did not receive measurement results!"); } return false; } else { for(int n=0; n<((2+(numObj*4))+owuShift); n++) { ultraMeasResult[n] = mySerial.read(); delay(1); } if (comm == 2) // OWU mode only { //rearrange array for OWU UMR results for(int n=0; n<(2+(numObj*4)); n++) { ultraMeasResult[n+1] = ultraMeasResult[n+owuShift]; //element 0 skipped due to no diagnostic field returned } } } } } else { //do nothing } return true; } double printUltrasonicMeasResult(byte umr) { int speedSound = 343; // speed of sound in air at room temperature printUltrasonicMeasResultExt(umr, speedSound); } byte printUltrasonicMeasResultRaw(byte umr) { return ultraMeasResult[umr]; } double printUltrasonicMeasResultExt(byte umr, int speedSound) { double objReturn = 0; double digitalDelay = 0; // TODO: compensates the burst time calculated as number_of_pulses/frequency. uint16_t objDist = 0; uint16_t objWidth = 0; uint16_t objAmp = 0; switch (umr) { case 0: //Obj1 Distance (m) { objDist = (ultraMeasResult[1]<<8) + ultraMeasResult[2]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 1: //Obj1 Width (us) { objWidth = ultraMeasResult[3]; objReturn= objWidth * 16; break; } case 2: //Obj1 Peak Amplitude { objAmp = ultraMeasResult[4]; objReturn= objAmp; break; } case 3: //Obj2 Distance (m) { objDist = (ultraMeasResult[5]<<8) + ultraMeasResult[6]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 4: //Obj2 Width (us) { objWidth = ultraMeasResult[7]; objReturn= objWidth * 16; break; } case 5: //Obj2 Peak Amplitude { objAmp = ultraMeasResult[8]; objReturn= objAmp; break; } case 6: //Obj3 Distance (m) { objDist = (ultraMeasResult[9]<<8) + ultraMeasResult[10]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 7: //Obj3 Width (us) { objWidth = ultraMeasResult[11]; objReturn= objWidth * 16; break; } case 8: //Obj3 Peak Amplitude { objAmp = ultraMeasResult[12]; objReturn= objAmp; break; } case 9: //Obj4 Distance (m) { objDist = (ultraMeasResult[13]<<8) + ultraMeasResult[14]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 10: //Obj4 Width (us) { objWidth = ultraMeasResult[15]; objReturn= objWidth * 16; break; } case 11: //Obj4 Peak Amplitude { objAmp = ultraMeasResult[16]; objReturn= objAmp; break; } case 12: //Obj5 Distance (m) { objDist = (ultraMeasResult[17]<<8) + ultraMeasResult[18]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 13: //Obj5 Width (us) { objWidth = ultraMeasResult[19]; objReturn= objWidth * 16; break; } case 14: //Obj5 Peak Amplitude { objAmp = ultraMeasResult[20]; objReturn= objAmp; break; } case 15: //Obj6 Distance (m) { objDist = (ultraMeasResult[21]<<8) + ultraMeasResult[22]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 16: //Obj6 Width (us) { objWidth = ultraMeasResult[23]; objReturn= objWidth * 16; break; } case 17: //Obj6 Peak Amplitude { objAmp = ultraMeasResult[24]; objReturn= objAmp; break; } case 18: //Obj7 Distance (m) { objDist = (ultraMeasResult[25]<<8) + ultraMeasResult[26]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 19: //Obj7 Width (us) { objWidth = ultraMeasResult[27]; objReturn= objWidth * 16; break; } case 20: //Obj7 Peak Amplitude { objAmp = ultraMeasResult[28]; objReturn= objAmp; break; } case 21: //Obj8 Distance (m) { objDist = (ultraMeasResult[29]<<8) + ultraMeasResult[30]; objReturn = (objDist/2*0.000001*speedSound) - digitalDelay; break; } case 22: //Obj8 Width (us) { objWidth = ultraMeasResult[31]; objReturn= objWidth * 16; break; } case 23: //Obj8 Peak Amplitude { objAmp = ultraMeasResult[32]; objReturn= objAmp; break; } default: Serial.println("ERROR - Invalid object result!"); break; } return objReturn; } void setup(){ Serial.begin(baudRate); mySerial.begin(baudRate); Serial.print("Init ... "); initBoostXLPGA460(commMode, baudRate, uartAddrUpdate); Serial.println("Done !"); } void loop() { // -+-+-+-+-+-+-+-+-+-+- PRESET 1 (SHORT RANGE) MEASUREMENT -+-+-+-+-+-+-+-+-+-+- // objectDetected = false; // Initialize object detected flag to false ultrasonicCmd(0,numOfObj); // run preset 1 (short distance) burst+listen for 1 object pullUltrasonicMeasResult(demoMode); // Pull Ultrasonic Measurement Result for (byte i=0; i<numOfObj; i++){ // Log uUltrasonic Measurement Result: Obj1: 0=Distance(m), 1=Width, 2=Amplitude; Obj2: 3=Distance(m), 4=Width, 5=Amplitude; etc.; distance = printUltrasonicMeasResult(0+(i*3)); //HEMA width = printUltrasonicMeasResult(1+(i*3)); // only available for UART, OWU, and SPI peak = printUltrasonicMeasResult(2+(i*3)); // only available for UART, OWU, and SPI delay(commandDelay); if (distance > minDistLim && distance < 11.2) // turn on DS1_LED if object is above minDistLim { Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Width (us): "); Serial.println(width); Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Amplitude (dec): "); Serial.println(peak); objectDetected = true; } } // -+-+-+-+-+-+-+-+-+-+- PRESET 2 (LONG RANGE) MEASUREMENT -+-+-+-+-+-+-+-+-+-+- // if(objectDetected == false || alwaysLong == true) // If no preset 1 (short distance) measurement result, switch to Preset 2 B+L command { ultrasonicCmd(1,numOfObj); // run preset 2 (long distance) burst+listen for 1 object pullUltrasonicMeasResult(demoMode); // Get Ultrasonic Measurement Result for (byte i=0; i<numOfObj; i++) { distance = printUltrasonicMeasResult(0+(i*3)); // Print Ultrasonic Measurement Result i.e. Obj1: 0=Distance(m), 1=Width, 2=Amplitude; Obj2: 3=Distance(m), 4=Width, 5=Amplitude; width = printUltrasonicMeasResult(1+(i*3)); // only available for UART, OWU, and SPI peak = printUltrasonicMeasResult(2+(i*3)); // only available for UART, OWU, and SPI delay(commandDelay); if (distance < 1 && distance > minDistLim) // turn on DS1_LED and F_DIAG_LED if object is within 1m { Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Width (us): "); Serial.println(width); Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Amplitude (dec): "); Serial.println(peak); objectDetected = true; } else if (distance < 3 && distance >= 1) // turn on DS1_LED and F_DIAG_LED if object is within 3m { Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); objectDetected = true; } else if (distance >= 3 && distance < 11.2) // turn on DS1_LED, F_DIAG_LED, and V_DIAG_LED if object is greater than 3m { Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); objectDetected = true; } else if (distance == 0 && commMode!=1) // turn off all LEDs if no object detected { Serial.print("Error reading measurement results..."); Serial.println(distance); } else //(distance > 11.2 && distance < minDistLim) // turn off all LEDs if no object detected or below minimum distance limit { if (i == numOfObj-1 && objectDetected == false) { Serial.println("No object..."); } } } } }

  • Another attempt that i have done,

    Using teensy board 3.6 with the official code,

    Here are my configurations and output,

    i connected the device through Tx1 and Rx1 on my board

    with 5v power input

    That is what i got :


    PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510
    --- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.
    --- To reset the program, and re-prompt for user input, enter a value of 'q'.
    --- To pause/resume the program when running, enter a value of 'p'.
    1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... 0
    2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... 0
    3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... 0
    4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... 72
    5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... 72
    6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... 72
    7. Minimum Distance = 0.1m * BYTE ... 1
    8. Run System Diagnostics?: 0=No, 1=Yes ... 1
    9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... 0
    10. Burn/Save User EEPROM?: 0=No, 1=Yes ... 0
    11. Command Cycle Delay: 100ms * BYTE ... 1
    12. Number of Objects to Detect (1-8) = BYTE ... 1
    13. USART Address of PGA460 (0-7) = BYTE ... 0
    Configuring the PGA460 with the selected settings. Wait...
    ERROR - Did not receive system diagnostics!
    System Diagnostics - Frequency (kHz): inf
    System Diagnostics - Decay Period (us): 0.00
    ERROR - Did not receive temp/noise!
    System Diagnostics - Die Temperature (C): -42.67
    ERROR - Did not receive temp/noise!
    System Diagnostics - Noise Level: 0.00
    ERROR - Did not receive measurement results!


  • Hello Tekomoro,

    Since you are seeking the ultrasonic measurement results, add a function in your main routine to help debug and read the following register values before executing a time-of-flight command.

    • Confirm bit THR_CRC_ERR = '0' after writing to the register space. If '1', then the threshold has not been updated, and the device will not burst or update the results.
    • Confirm bitDATADUMP_EN = '0' (default) to update the ultrasonic measurement result values instead of the echo data dump memory

    You can use the Energia library's byte pga460::registerRead(byte addr)  function as an example of implementing a register read command.

    Ensure you have added sufficient delay between the beginning of you time-of-flight command (burst/listen) and when you read back the ultrasonic measurement results. For debug purposes, set this delay to 100ms since the preset record length maximum is 65ms.

    Ensure you have setup your UART master with 2-stop bits. The default UART for most MCUs is to only have 1-stop bit.

    You can also oscilloscope prove the transducer's positive terminal to check if the device is actually bursting the transducer to generate an echo.

    When you get a response from the PGA460, what is the value of the diagnostic field (the first byte)? It should always read 0x40 if the last command sent was successfully received and processed.

    I am unable to open your source code file. Feel free to post your code's text directly to this thread.

  • Hello Akeem,

    I printed out the Values

    THR_CRC_ERR: 0

    DATADUMP_EN: 0

    and it still gives me no object

    OUTPUT SAMPLE:

    PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510
    --- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.
    --- To reset the program, and re-prompt for user input, enter a value of 'q'.
    --- To pause/resume the program when running, enter a value of 'p'.
    1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... 0
    2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... 5
    3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... 0
    4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... 72
    5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... 72
    6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... 72
    7. Minimum Distance = 0.1m * BYTE ... 1
    8. Run System Diagnostics?: 0=No, 1=Yes ... 0
    9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... 0
    10. Burn/Save User EEPROM?: 0=No, 1=Yes ... 0
    11. Command Cycle Delay: 100ms * BYTE ... 2
    12. Number of Objects to Detect (1-8) = BYTE ... 1
    13. USART Address of PGA460 (0-7) = BYTE ... 0
    Configuring the PGA460 with the selected settings. Wait...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    

    My code is 5 files:

    Hint: I am not interested in SPI Communication

    CODE:

    /*------------------------------------------------- GetDistance -----
     PROJECT:     PGA460 UART, TCI, OWU, & SPI Ultrasonic Time-of-Flight
     DESCRIPTION: Transmits and receives ultrasonic echo data to measure 
                  time-of-flight distance, width, and/or amplitude. 
     CREATED:     22 February 2017
     UPDATED:     31 July 2019
     REVISION:    D
     AUTHOR:      A. Whitehead
     NOTES:       This example code is in the public domain.
    *-------------------------------------------------------------------*/
    #include "PGA460_USSC.h"
    /*------------------------------------------------- run mode -----
    |  userInputMode
    |
    |  Purpose:  This code can be operated in two run modes: 
    |    • userInputMode = allows the user to configure the device using
    |      the COM serial terminal. Resulting data is printed in the
    |      terminal view. Recommended run mode.
    |    • standAloneMode = waits for the user to press the
    |      LaucnhPad's PUSH2 button to automatically execute the
    |      initializaiton routine, and begin the burst-and-listen captures.
    |      The device is configured based on the hard-coded global 
    |      variables. LEDs are illumanted to represent approximate
    |      object distance. Results also printed on serial COM terminal.
    |      Comment out the run mode to use standAloneMode.
    *-------------------------------------------------------------------*/
    #define userInputMode
    /*------------------------------------------------- Global Variables -----
    |  Global Variables
    |
    |  Purpose:  Variables shared throughout the GetDistance sketch for 
    |    both userInput and standAlone modes. Hard-code these values to
    |    the desired conditions when automatically updating the device
    |    in standAlone mode.
    *-------------------------------------------------------------------*/
    
    // Configuration variables
      byte commMode = 0;            // Communication mode: 0=UART, 1=TCI, 2=OneWireUART
      byte fixedThr = 1;            // set P1 and P2 thresholds to 0=%25, 1=50%, or 2=75% of max; initial minDistLim (i.e. 20cm) ignored
      byte xdcr = 1;                // set PGA460 to recommended settings for 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R
      byte agrTVG = 2;              // set TVG's analog front end gain range to 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB
      byte fixedTVG = 1;            // set fixed TVG level at 0=%25, 1=50%, or 1=75% of max
      byte runDiag = 0;             // run system diagnostics and temp/noise level before looping burst+listen command
      byte edd = 0;                 // echo data dump of preset 1, 2, or neither
      byte burn = 0;                // trigger EE_CNTRL to burn and program user EEPROM memory
      byte cdMultiplier = 1;        // multiplier for command cycle delay
      byte numOfObj = 1;            // number of object to detect set to 1-8
      byte uartAddrUpdate = 0;      // PGA460 UART address to interface to; default is 0, possible address 0-7
      bool objectDetected = false;  // object detected flag to break burst+listen cycle when true
      bool demoMode = false;        // only true when running UART/OWU multi device demo mode
      bool alwaysLong = false;      // always run preset 2, regardless of preset 1 result (hard-coded only)
      double minDistLim = 0.1;      // minimum distance as limited by ringing decay of single transducer and threshold masking
      uint16_t commandDelay = 0;    // Delay between each P1 and Preset 2 command
      uint32_t baudRate = 115200;     // UART baud rate: 9600, 19200, 38400, 57600, 74800, 115200 
    
    
    // Result variables
      double distance = 0;          // one-way object distance in meters
      double width = 0;             // object width in microseconds
      double peak = 0;              // object peak in 8-bit
      double diagnostics = 0;       // diagnostic selector
      byte echoDataDumpElement = 0; // echo data dump element 0 to 127
      String interruptString = "";  // a string to hold incoming data
      boolean stringComplete = false; // whether the string is complete
    
    // PGA460_USSC library class
      pga460 ussc;
    
    /*------------------------------------------------- setup -----
    |  function Setup
    |
    |  Purpose: (see funciton initPGA460 for details)
    *-------------------------------------------------------------------*/
    void setup() {                // put your setup code here, to run once
      initPGA460(); 
      }
    
    /*------------------------------------------------- initPGA460 -----
    |  function initPGA460
    |
    |  Purpose: One-time setup of PGA460-Q1 EVM hardware and software 
    |      in the following steps: 
    |    1) Configure the master to operate in UART, TCI, or OWU 
    |      communication mode.
    |    2) Confgiure the EVM for compatiblity based on the selected 
    |      communicaton mode.
    |    3) Option to update user EEPROM and threhsold registers with 
    |      pre-defined values.
    |    4) Option to burn the EEPROM settings (not required unless 
    |      values are to be preserved after power cycling device).
    |    5) Option to report echo data dump and/or system diagnostics.
    |  
    |  In userInput mode, the user is prompted to enter values through 
    |   the Serial COM terminal to configure the device.
    |
    |  In standAlone mode, the user must hard-code the configuration 
    |   variables in the globals section for the device to 
    |   auto-configure in the background.
    *-------------------------------------------------------------------*/
    void initPGA460() {
      
        #ifdef userInputMode
        int inByte = 0;         // incoming serial byte    
        
        Serial.begin(baudRate); // initialize COM UART serial channel
        delay(1000);
        Serial.println("PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight");
        Serial.println("-------------------------------------------------------------------------");
        Serial.println("Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.");
        Serial.println("--- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510");
        Serial.println("--- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.");
        Serial.println("--- To reset the program, and re-prompt for user input, enter a value of 'q'.");
        Serial.println("--- To pause/resume the program when running, enter a value of 'p'.");
        
        int numInputs = 13;
        for (int i=0; i<numInputs; i++)
        {
          switch(i)
          {
            case 0: Serial.print("1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... "); break;     
            case 1: 
              if(commMode == 0 || commMode == 1 || commMode == 2) // UART, OWU, or TCI
              {
                Serial.print("2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... "); break;
              }
              else if (commMode == 3) // SPI
              {
                Serial.print("2. Clock Divider (MHz): 0=16/1, 1=16/2, 2=16/4, 3=16/8, 4=16/16, 5=16/32, 6=16/64, 7=16/128 ... "); break;
              }                          
            case 2: Serial.print("3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... "); break;   
            case 3: Serial.print("4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... "); break;  
            case 4: Serial.print("5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... "); break;   
            case 5: Serial.print("6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... "); break;     
            case 6: Serial.print("7. Minimum Distance = 0.1m * BYTE ... "); break; 
            case 7: Serial.print("8. Run System Diagnostics?: 0=No, 1=Yes ... "); break;
            case 8: Serial.print("9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... "); break;
            case 9: Serial.print("10. Burn/Save User EEPROM?: 0=No, 1=Yes ... "); break;
            case 10: Serial.print("11. Command Cycle Delay: 100ms * BYTE ... "); break;
            case 11: Serial.print("12. Number of Objects to Detect (1-8) = BYTE ... "); break;
            case 12: Serial.print("13. USART Address of PGA460 (0-7) = BYTE ... "); break;
          }
    
          // only accept input as valid if 0-9, q, s, or x; otherwise, wait until valid input
          bool validInput = false;
          while (validInput == false)
          {
            while (Serial.available() == 0){}
            inByte = Serial.read();
             if (inByte==48 || inByte==49 || inByte==50 || inByte==51 ||
            inByte==52 || inByte==53 || inByte==54 || inByte==55 || 
            inByte==56 || inByte==57 || inByte==113 || inByte==115 || inByte==120)
            {
              validInput = true; // valid input, break while loop       
            }
            else
            {
              // not a valid value   
            }
          } 
          
          //subtract 48d since ASCII '0' is 48d as a printable character   
          inByte = inByte - 48;   
          if (inByte != 115-48 && inByte != 113-48) // if input is neither 's' or 'q'
          {        
            delay(300);
            Serial.println(inByte);
            switch(i)
            {
              case 0: commMode = inByte; break;     
              case 1: 
                if(commMode == 0 || commMode == 1 || commMode == 2) // UART, OWU, or TCI
                {
                  switch(inByte)
                  {
                    case 0: baudRate=9600; break;
                    case 1: baudRate=19200; break; 
                    case 2: baudRate=38400; break; 
                    case 3: baudRate=57600; break; 
                    case 4: baudRate=74800; break;
                    case 5: baudRate=115200; break; 
                    default: baudRate=9600; break;   
                  }
                }
                else if (commMode == 3) // SPI
                {
                  switch(inByte)
                  {
                    case 0: baudRate=1; break;
                    case 1: baudRate=2; break; 
                    case 2: baudRate=4; break; 
                    case 3: baudRate=8; break; 
                    case 4: baudRate=16; break;
                    case 5: baudRate=32; break; 
                    case 6: baudRate=64; break;
                    case 7: baudRate=128; break;
                    default: baudRate=16; break; 
                  }
                } 
                else
                {
                  baudRate = inByte; 
                }
                break;
              case 2: fixedThr = inByte; break;   
              case 3: xdcr = inByte; break;   
              case 4: agrTVG = inByte; break;   
              case 5: fixedTVG = inByte; break;     
              case 6: minDistLim = inByte * 0.1; break;
              case 7: runDiag = inByte; break;  
              case 8: edd = inByte; break;
              case 9: burn = inByte; break;
              case 10: cdMultiplier = inByte; break;  
              case 11: numOfObj = inByte; break;
              case 12: uartAddrUpdate = inByte; break;
              default: break;
            }
          }
          else if(inByte == 113-48) //  'q'
          {
            initPGA460(); // restart initializaiton routine
          }
          else //   's'
          {
            i=numInputs-1; // force for-loop to break
            Serial.println("");        
          }      
        }    
         
        Serial.println("Configuring the PGA460 with the selected settings. Wait...");
        delay(300);
    
      #else  // standAlone mode  
        pinMode(buttonPin, INPUT_PULLUP);         // initialize the pushbutton pin as an input
        while (digitalRead(buttonPin) == HIGH){}  // wait until user presses PUSH2 button to run standalone mode
      #endif
    
    /*------------------------------------------------- userInput & standAlone mode initialization -----
      Configure the EVM in the following order:
      1) Select PGA460 interface, device baud, and COM terminal baud up to 115.2k for targeted address.
      2) Bulk write all threshold values to clear the THR_CRC_ERR.
      3) Bulk write user EEPROM with pre-define values in PGA460_USSC.c. 
      4) Update analog front end gain range, and bulk write TVG.
      5) Run system diagnostics for frequency, decay, temperature, and noise measurements
      6) Program (burn) EEPROM memory to save user EEPROM values
      7) Run a preset 1 or 2 burst and/or listen command to capture the echo data dump  
      
      if the input is 'x' (72d), then skip that configuration
    *-------------------------------------------------------------------*/
      // -+-+-+-+-+-+-+-+-+-+- 1 : interface setup   -+-+-+-+-+-+-+-+-+-+- //
        ussc.initBoostXLPGA460(commMode, baudRate, uartAddrUpdate); 
        
      // -+-+-+-+-+-+-+-+-+-+- 2 : bulk threshold write   -+-+-+-+-+-+-+-+-+-+- //
        if (fixedThr != 72){ussc.initThresholds(fixedThr);} 
      // -+-+-+-+-+-+-+-+-+-+- 3 : bulk user EEPROM write   -+-+-+-+-+-+-+-+-+-+- //
        if (xdcr != 72){ussc.defaultPGA460(xdcr);}
      // -+-+-+-+-+-+-+-+-+-+- 4 : bulk TVG write   -+-+-+-+-+-+-+-+-+-+- //
        if (agrTVG != 72 && fixedTVG != 72){ussc.initTVG(agrTVG,fixedTVG);}
      // -+-+-+-+-+-+-+-+-+-+- 5 : run system diagnostics   -+-+-+-+-+-+-+-+-+-+- //
        if (runDiag == 1)
        {      
          diagnostics = ussc.runDiagnostics(1,0);       // run and capture system diagnostics, and print freq diag result
          Serial.print("System Diagnostics - Frequency (kHz): "); Serial.println(diagnostics);
          diagnostics = ussc.runDiagnostics(0,1);       // do not re-run system diagnostic, but print decay diag result
          Serial.print("System Diagnostics - Decay Period (us): "); Serial.println(diagnostics);
          diagnostics = ussc.runDiagnostics(0,2);       // do not re-run system diagnostic, but print temperature measurement
          Serial.print("System Diagnostics - Die Temperature (C): "); Serial.println(diagnostics);
          diagnostics = ussc.runDiagnostics(0,3);       // do not re-run system diagnostic, but print noise level measurement
          Serial.print("System Diagnostics - Noise Level: "); Serial.println(diagnostics);
        }
      // -+-+-+-+-+-+-+-+-+-+- 6 : burn EEPROM   -+-+-+-+-+-+-+-+-+-+- //
        if(burn == 1)
        {
          byte burnStat = ussc.burnEEPROM();
          if(burnStat == true){Serial.println("EEPROM programmed successfully.");}
          else{Serial.println("EEPROM program failed.");}
        }
      // -+-+-+-+-+-+-+-+-+-+- 7 : capture echo data dump   -+-+-+-+-+-+-+-+-+-+- //
        if (edd != 0)                                   // run or skip echo data dump
        {
          Serial.println("Retrieving echo data dump profile. Wait...");
          ussc.runEchoDataDump(edd-1);                  // run preset 1 or 2 burst and/or listen command
          Serial.print(ussc.pullEchoDataDumpBulk());
          Serial.println("");
        }
      // -+-+-+-+-+-+-+-+-+-+-  others   -+-+-+-+-+-+-+-+-+-+- //
      commandDelay = 100 * cdMultiplier;                   // command cycle delay result in ms
      if (numOfObj == 0 || numOfObj >8) { numOfObj = 1; } // sets number of objects to detect to 1 if invalid input                      
    
    }
    
    /*------------------------------------------------- main loop -----
    |  main loop  GetDistance
    |
    |   The PGA460 is initiated with a Preset 1 Burst-and-Listen 
    |     Time-of-Flight measurement. Preset 1 is ideally configured for 
    |     short-range measurements (sub-1m range) when using the pre-defined 
    |     user EEPROM configurations.
    |
    |   If no object is detected, the PGA460 will then be issued a 
    |     Preset 2 Burst-and-Listen Time-of-Flight measurement. 
    |     Preset 2 is configured for long-range measurements (beyond 
    |     1m range). 
    |
    |   Depending on the resulting distance, the diagnostics LEDs will 
    |     illuminate to represent a short, mid, or long range value.
    |   
    |   In userInput mode, the distance, width, and/or amplitude value 
    |     of each object is serial printed on the COM terminal.
    |
    |   In standAlone mode, only distance can be represented visually 
    |     on the LEDs. The resulting values are still serial printed 
    |     on a COM terminal for debug, and to view the numerical values 
    |     of the data captured.
    |
    *-------------------------------------------------------------------*/
    
    void loop() {                 // put your main code here, to run repeatedly
        // -+-+-+-+-+-+-+-+-+-+-  PRESET 1 (SHORT RANGE) MEASUREMENT   -+-+-+-+-+-+-+-+-+-+- //
          Serial.print("THR_CRC_ERR: ");
          Serial.println(ussc.registerRead(byte(0x4C)), BIN);

          Serial.print("DATADUMP_EN: ");
          Serial.println(ussc.registerRead(byte(0x40)), BIN); objectDetected = false; // Initialize object detected flag to false ussc.ultrasonicCmd(0,numOfObj); // run preset 1 (short distance) burst+listen for 1 object ussc.pullUltrasonicMeasResult(demoMode); // Pull Ultrasonic Measurement Result for (byte i=0; i<numOfObj; i++) { // Log uUltrasonic Measurement Result: Obj1: 0=Distance(m), 1=Width, 2=Amplitude; Obj2: 3=Distance(m), 4=Width, 5=Amplitude; etc.; distance = ussc.printUltrasonicMeasResult(0+(i*3)); //width = ussc.printUltrasonicMeasResult(1+(i*3)); // only available for UART, OWU, and SPI //peak = ussc.printUltrasonicMeasResult(2+(i*3)); // only available for UART, OWU, and SPI delay(commandDelay); if (distance > minDistLim && distance < 11.2) // turn on DS1_LED if object is above minDistLim { ussc.toggleLEDs(HIGH,LOW,LOW); Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); //Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Width (us): "); Serial.println(width); //Serial.print("P1 Obj"); Serial.print(i+1); Serial.print(" Amplitude (dec): "); Serial.println(peak); objectDetected = true; } } // -+-+-+-+-+-+-+-+-+-+- PRESET 2 (LONG RANGE) MEASUREMENT -+-+-+-+-+-+-+-+-+-+- // if(objectDetected == false || alwaysLong == true) // If no preset 1 (short distance) measurement result, switch to Preset 2 B+L command { ussc.ultrasonicCmd(1,numOfObj); // run preset 2 (long distance) burst+listen for 1 object ussc.pullUltrasonicMeasResult(demoMode); // Get Ultrasonic Measurement Result for (byte i=0; i<numOfObj; i++) { distance = ussc.printUltrasonicMeasResult(0+(i*3)); // Print Ultrasonic Measurement Result i.e. Obj1: 0=Distance(m), 1=Width, 2=Amplitude; Obj2: 3=Distance(m), 4=Width, 5=Amplitude; //width = ussc.printUltrasonicMeasResult(1+(i*3)); // only available for UART, OWU, and SPI //peak = ussc.printUltrasonicMeasResult(2+(i*3)); // only available for UART, OWU, and SPI delay(commandDelay); if (distance < 1 && distance > minDistLim) // turn on DS1_LED and F_DIAG_LED if object is within 1m { ussc.toggleLEDs(HIGH,LOW,LOW); Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); //Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Width (us): "); Serial.println(width); //Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Amplitude (dec): "); Serial.println(peak); objectDetected = true; } else if (distance < 3 && distance >= 1) // turn on DS1_LED and F_DIAG_LED if object is within 3m { ussc.toggleLEDs(HIGH,HIGH,LOW); Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); objectDetected = true; } else if (distance >= 3 && distance < 11.2) // turn on DS1_LED, F_DIAG_LED, and V_DIAG_LED if object is greater than 3m { ussc.toggleLEDs(HIGH,HIGH,HIGH); Serial.print("P2 Obj"); Serial.print(i+1); Serial.print(" Distance (m): "); Serial.println(distance); objectDetected = true; } else if (distance == 0 && commMode!=1) // turn off all LEDs if no object detected { ussc.toggleLEDs(LOW,LOW,LOW); //Serial.print("Error reading measurement results..."); //Serial.println(distance); } else //(distance > 11.2 && distance < minDistLim) // turn off all LEDs if no object detected or below minimum distance limit { if (i == numOfObj-1 && objectDetected == false) { ussc.toggleLEDs(LOW,LOW,LOW); Serial.println("No object..."); } } } } } // -+-+-+-+-+-+-+-+-+-+- SERIAL MONITORING -+-+-+-+-+-+-+-+-+-+- // /* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */ void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); // get the new byte // if the incoming character is a 'q', set a flag, stop the main loop, and re-run initialization if (inChar == 'q'){stringComplete = true; initPGA460();} // if the incoming character is a 'p', set a flag, pause the loop, and resume loop upon receiving another 'p' character else if (inChar == 'p') { Serial.println("PAUSE"); stringComplete = false; while(stringComplete == false) { while (Serial.available()) { inChar = (char)Serial.read(); // get the new byte if (inChar == 'p') { stringComplete = true; } if (inChar == 'q') { stringComplete = true; initPGA460(); } delay(1000); } } stringComplete=false; Serial.println(""); } else {} //do nothing } }

    PGA460_USSC.cpp

    /*
    	PGA460_USSC.cpp
    	
    	BSD 2-clause "Simplified" License
    	Copyright (c) 2017, Texas Instruments
    	All rights reserved.
    
    	Redistribution and use in source and binary forms, with or without
    	modification, are permitted provided that the following conditions are met:
    
    	1. Redistributions of source code must retain the above copyright notice, this
    	   list of conditions and the following disclaimer.
    	2. Redistributions in binary form must reproduce the above copyright notice,
    	   this list of conditions and the following disclaimer in the documentation
    	   and/or other materials provided with the distribution.
    
    	THIS SOFTWARE IS PROVIDED BY TEXAS INSTRUMENTS "AS IS" AND
    	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    	DISCLAIMED. IN NO EVENT SHALL TEXAS INSTRUMENTS BE LIABLE FOR
    	ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    	The views and conclusions contained in the software and documentation are those
    	of the authors and should not be interpreted as representing official policies,
    	either expressed or implied, of the FreeBSD Project.
    	
    	Last Updated: Jul 2019
    	By: A. Whitehead <make@energia.nu>
    */
    
    #include "PGA460_USSC.h"
    #include "PGA460_SPI.h"
    #include "Energia.h"
    
    #define EnUART		//enables UART communication at TXD and RXD
    #define EnOWU		//enables OWU communication at IO
    #define EnTCI		//enables TCI communication at TCI
    #define EnSPI		//enables SPI communication at TXD, RXD, and SCLK
    #define EnTri		//enables triangulation
    #define EnAutoThr	//enables autotset thresholding
    
    /*------------------------------------------------- Global Variables -----
     |  Global Variables
     |
     |  Purpose:  Variables shared throughout the PGA460_USSC.cpp functions
     *-------------------------------------------------------------------*/
    #pragma region globals
    // Pin mapping of BOOSTXL-PGA460 to LaunchPad by pin name
    	#define DECPL_A 2
    	#define RXD_LP 3
    	#define TXD_LP 4
    	#define DECPL_D 5
    	#define TEST_A 6
    	#define TCI_CLK 7
    	#define TEST_D 8
    	#define MEM_SOMI 9
    	#define MEM_SIMO 10
    	#define TCI_RX 14
    	#define TCI_TX 15
    	#define COM_SEL 17
    	#define COM_PD 18
    	#define SPI_CS 33
    	#define SCLK_CLK 34
    	#define MEM_HOLD 36
    	#define MEM_CS 37
    	#define DS1_LED 38
    	#define F_DIAG_LED 39
    	#define V_DIAG_LED 40
    
    // Serial read timeout in milliseconds
    	#define MAX_MILLIS_TO_WAIT 250
    
    // Define UART commands by name
    	// Single Address
    		byte P1BL = 0x00;
    		byte P2BL = 0x01;
    		byte P1LO = 0x02;
    		byte P2LO = 0x03;
    		byte TNLM = 0x04;
    		byte UMR = 0x05;
    		byte TNLR = 0x06;
    		byte TEDD = 0x07;
    		byte SD = 0x08;
    		byte SRR = 0x09; 
    		byte SRW = 0x0A;
    		byte EEBR = 0x0B;
    		byte EEBW = 0x0C;
    		byte TVGBR = 0x0D;
    		byte TVGBW = 0x0E;
    		byte THRBR = 0x0F;
    		byte THRBW = 0x10; 
    	//Broadcast
    		byte BC_P1BL = 0x11;
    		byte BC_P2BL = 0x12;
    		byte BC_P1LO = 0x13;
    		byte BC_P2LO = 0x14;
    		byte BC_TNLM = 0x15;
    		byte BC_RW = 0x16;
    		byte BC_EEBW = 0x17;
    		byte BC_TVGBW = 0x18;
    		byte BC_THRBW = 0x19;
    		//CMDs 26-31 are reserved
    
    // List user registers by name with default settings from TI factory
    	byte USER_DATA1 = 0x00;
    	byte USER_DATA2 = 0x00;
    	byte USER_DATA3 = 0x00;
    	byte USER_DATA4 = 0x00;
    	byte USER_DATA5 = 0x00;
    	byte USER_DATA6 = 0x00;
    	byte USER_DATA7 = 0x00;
    	byte USER_DATA8 = 0x00;
    	byte USER_DATA9 = 0x00;
    	byte USER_DATA10 = 0x00;
    	byte USER_DATA11 = 0x00;
    	byte USER_DATA12 = 0x00;
    	byte USER_DATA13 = 0x00;
    	byte USER_DATA14 = 0x00;
    	byte USER_DATA15 = 0x00;
    	byte USER_DATA16 = 0x00;
    	byte USER_DATA17 = 0x00;
    	byte USER_DATA18 = 0x00;
    	byte USER_DATA19 = 0x00;
    	byte USER_DATA20 = 0x00;
    	byte TVGAIN0 = 0xAF;
    	byte TVGAIN1 = 0xFF;
    	byte TVGAIN2 = 0xFF;
    	byte TVGAIN3 = 0x2D;
    	byte TVGAIN4 = 0x68;
    	byte TVGAIN5 = 0x36;
    	byte TVGAIN6 = 0xFC;
    	byte INIT_GAIN = 0xC0;
    	byte FREQUENCY  = 0x8C;
    	byte DEADTIME = 0x00;
    	byte PULSE_P1 = 0x01;
    	byte PULSE_P2 = 0x12;
    	byte CURR_LIM_P1 = 0x47;
    	byte CURR_LIM_P2 = 0xFF;
    	byte REC_LENGTH = 0x1C;
    	byte FREQ_DIAG = 0x00;
    	byte SAT_FDIAG_TH = 0xEE;
    	byte FVOLT_DEC = 0x7C;
    	byte DECPL_TEMP = 0x0A;
    	byte DSP_SCALE = 0x00;
    	byte TEMP_TRIM = 0x00;
    	byte P1_GAIN_CTRL = 0x00;
    	byte P2_GAIN_CTRL = 0x00;
    	byte EE_CRC = 0xFF;
    	byte EE_CNTRL = 0x00;
    	byte P1_THR_0 = 0x88;
    	byte P1_THR_1 = 0x88;
    	byte P1_THR_2 = 0x88;
    	byte P1_THR_3 = 0x88;
    	byte P1_THR_4 = 0x88;
    	byte P1_THR_5 = 0x88;
    	byte P1_THR_6 = 0x84;
    	byte P1_THR_7 = 0x21;
    	byte P1_THR_8 = 0x08;
    	byte P1_THR_9 = 0x42;
    	byte P1_THR_10 = 0x10;
    	byte P1_THR_11 = 0x80;
    	byte P1_THR_12 = 0x80;
    	byte P1_THR_13 = 0x80;
    	byte P1_THR_14 = 0x80;
    	byte P1_THR_15 = 0x80;
    	byte P2_THR_0 = 0x88;
    	byte P2_THR_1 = 0x88;
    	byte P2_THR_2 = 0x88;
    	byte P2_THR_3 = 0x88;
    	byte P2_THR_4 = 0x88;
    	byte P2_THR_5 = 0x88;
    	byte P2_THR_6 = 0x84;
    	byte P2_THR_7 = 0x21;
    	byte P2_THR_8 = 0x08;
    	byte P2_THR_9 = 0x42;
    	byte P2_THR_10 = 0x10;
    	byte P2_THR_11 = 0x80;
    	byte P2_THR_12 = 0x80;
    	byte P2_THR_13 = 0x80;
    	byte P2_THR_14 = 0x80;
    	byte P2_THR_15 = 0x80;
    
    // Miscellaneous variables; (+) indicates OWU transmitted byte offset
    	byte checksum = 0x00; 			// UART checksum value	
    	byte ChecksumInput[44]; 		// data byte array for checksum calculator
    	byte ultraMeasResult[34+3]; 	// data byte array for cmd5 and tciB+L return
    	byte diagMeasResult[5+3]; 		// data byte array for cmd8 and index1 return
    	byte tempNoiseMeasResult[4+3]; 	// data byte array for cmd6 and index0&1 return
    	byte echoDataDump[130+3]; 		// data byte array for cmd7 and index12 return
    	byte tempOrNoise = 0; 			// data byte to determine if temp or noise measurement is to be performed
    	byte comm = 0; 					// indicates UART (0), TCI (1), OWU (2) communication mode	
    	unsigned long starttime; 		// used for function time out
    	byte bulkThr[34+3];				// data byte array for bulk threhsold commands
    	//UART & OWU exclusive variables
    		byte syncByte = 0x55; 		// data byte for Sync field set UART baud rate of PGA460
    		byte regAddr = 0x00; 		// data byte for Register Address
    		byte regData = 0x00; 		// data byte for Register Data
    		byte uartAddr = 0; 			// PGA460 UART device address (0-7). '0' is factory default address
    		byte numObj = 1; 			// number of objects to detect
    		//OWU exclusive variables
    			signed int owuShift = 0;	// accoutns for OWU receiver buffer offset for capturing master transmitted data - always 0 for standard two-wire UART
    	//TCI exclusive variables
    		byte bufRecv[128]; 				// TCI receive data buffer for all commands	
    		unsigned long tciToggle;		// used to log TCI burst+listen time of object
    		unsigned int objTime[8];		// array to capture up to eight object TCI burst+listen toggles
    	//SPI exclusive variables
    		byte misoBuf[131]; 				// SPI MISO receive data buffer for all commands	
    #pragma endregion globals
    
    /*------------------------------------------------- PGA460 Top Level -----
     |  PGA460 Top Level Scope Resolution Operator
     |
     | Use the double colon operator (::) to qualify a C++ member function, a top
     | level function, or a variable with global scope with:
     | • An overloaded name (same name used with different argument types)
     | • An ambiguous name (same name used in different classes)
     *-------------------------------------------------------------------*/
    pga460::pga460(){}
    
    /*------------------------------------------------- initBoostXLPGA460 -----
     |  Function initBoostXLPGA460
     |
     |  Purpose:  Configure the master communication mode and BOOSTXL-PGA460 hardware to operate in UART, TCI, or OWU mode.
     |  Configures master serial baud rate for UART/OWU modes. Updates UART address based on sketch input.
     |
     |  Parameters:
     |		mode (IN) -- sets communicaiton mode. 
     |			0=UART 
     |			1=TCI 
     |			2=OWU 
     |			3-SPI (Synchronous Mode)
     |			4 = Not Used
     |			5 = Not Used
     |			6=Bus_Demo_Bulk_TVG_or_Threshold_Broadcast_is_True
     |			7=Bus_Demo_UART_Mode
     |			8=Bus_Demo_OWU_One_Time_Setup
     |			9=Bus_Demo_OWU_Mode
     | 		baud (IN) -- PGA460 accepts a baud rate of 9600 to 115.2k bps
     | 		uartAddrUpdate (IN) -- PGA460 address range from 0 to 7
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::initBoostXLPGA460(byte mode, uint32_t baud, byte uartAddrUpdate)
    {
    	// check for valid UART address
    	if (uartAddrUpdate > 7)
    	{
    		uartAddrUpdate = 0; // default to '0'
    		Serial.println("ERROR - Invalid UART Address!");
    	}
    	// globally update target PGA460 UART address and commands	
    	if (uartAddr != uartAddrUpdate)
    	{
    		// Update commands to account for new UART addr
    		  // Single Address
    		   P1BL = 0x00 + (uartAddrUpdate << 5);	   
    		   P2BL = 0x01 + (uartAddrUpdate << 5);
    		   P1LO = 0x02 + (uartAddrUpdate << 5);
    		   P2LO = 0x03 + (uartAddrUpdate << 5);
    		   TNLM = 0x04 + (uartAddrUpdate << 5);
    		   UMR = 0x05 + (uartAddrUpdate << 5);
    		   TNLR = 0x06 + (uartAddrUpdate << 5);
    		   TEDD = 0x07 + (uartAddrUpdate << 5);
    		   SD = 0x08 + (uartAddrUpdate << 5);
    		   SRR = 0x09 + (uartAddrUpdate << 5); 
    		   SRW = 0x0A + (uartAddrUpdate << 5);
    		   EEBR = 0x0B + (uartAddrUpdate << 5);
    		   EEBW = 0x0C + (uartAddrUpdate << 5);
    		   TVGBR = 0x0D + (uartAddrUpdate << 5);
    		   TVGBW = 0x0E + (uartAddrUpdate << 5);
    		   THRBR = 0x0F + (uartAddrUpdate << 5);
    		   THRBW = 0x10 + (uartAddrUpdate << 5); 
    	}
    	uartAddr = uartAddrUpdate;
    	
    
    	// turn off BOOSTXL-PGA460's diagnostic LEDs
    	pinMode(DS1_LED, OUTPUT); digitalWrite(DS1_LED, LOW);
    	pinMode(F_DIAG_LED, OUTPUT); digitalWrite(F_DIAG_LED, LOW);
    	pinMode(V_DIAG_LED, OUTPUT); digitalWrite(V_DIAG_LED, LOW);
    
    	// set communication mode flag
    	if (mode < 4) // 0=UART, 1=TCI, 2=OWU, 3=SPI
    	{
    		comm = mode;
    		// disable synchronous mode dump to external memory
    		pinMode(MEM_HOLD, OUTPUT);  digitalWrite(MEM_HOLD, HIGH);
    		pinMode(MEM_CS, OUTPUT);  digitalWrite(MEM_CS, HIGH);
    	}
    	else if (mode == 6) 
    	{
    		comm = 6; // bus demo user input mode only, and threshold or TVG bulk write broadcast commands are true
    	}
    	else if ((mode == 7) || (mode == 9)) 
    	{
    		comm = mode - 7; // bus demo only for either UART or OWU mode
    	}
    	else
    	{
    		comm = 99; // invalid communication type
    	}
    	
    	switch (mode)
    	{
    		case 0: // UART Mode
    			// enable PGA460 UART communication mode
    			pinMode(COM_PD, OUTPUT);  digitalWrite(COM_PD, LOW);
    			pinMode(COM_SEL, OUTPUT);  digitalWrite(COM_SEL, LOW);
    			Serial.begin(baud); 	// initialize COM UART serial channel
    			Serial1.begin(baud);	// initialize PGA460 UART serial channel
    			Serial1.setTimeout(250);
    			break;
    		case 1: //TCI Mode	
    			// enable PGA460 TCI communication mode
    			pinMode(COM_PD, OUTPUT);  digitalWrite(COM_PD, LOW);
    			pinMode(COM_SEL, OUTPUT);  digitalWrite(COM_SEL, LOW);
    			pinMode(TCI_TX, OUTPUT); digitalWrite(TCI_TX, HIGH);
    			pinMode(TCI_RX, INPUT_PULLUP);
    			Serial.begin(baud); 	// initialize COM UART serial channel
    			Serial1.begin(baud);	// initialize PGA460 UART serial channel
    			Serial1.setTimeout(250);
    			break;
    		case 2: //OWU setup (part I)
    			// enable PGA460 UART communication mode
    			pinMode(COM_PD, OUTPUT);  digitalWrite(COM_PD, LOW);
    			pinMode(COM_SEL, OUTPUT);  digitalWrite(COM_SEL, LOW);
    			Serial.begin(baud); 	// initialize COM UART serial channel
    			Serial1.begin(baud);	// initialize PGA460 UART serial channel
    			PULSE_P1 = 0x80 | PULSE_P1; // update IO_IF_SEL bit to '1' for OWU mode for bulk EEPROM write
    			break;			
    		case 3: // SPI mode			
    			usscSPI.begin();            	// start the SPI for BOOSTXL-PGA460 library
    			usscSPI.setBitOrder(0);     	// set bit order to LSB first
    			//In this mode the USART interface acts as a serial-shift register with data set on the rising edge of the clock and sampled on the falling edge of the clock.
    			usscSPI.setDataMode(2);     	// set the data mode for clock is High when inactive (CPOL=1) & data is valid on clock leading edge (CPHA = 0) (SPI_MODE2)
    			usscSPI.setClockDivider(baud); 	// set clock divider (16MHz master)			
    			Serial.begin(9600); 			// initialize COM UART serial channel
    			break;
    			
    		default: break;
    	}
    	
    	//OWU setup (part II)
    	if ((comm == 2) || (mode == 8)) // mode8 is for one time setup of OWU per slave device for bus demo
    	{
    		// UART write to register PULSE_P1 (addr 0x1E) to set device into OWU mode
    		regAddr = 0x1E;
    		regData = PULSE_P1;
    		byte buf10[5] = {syncByte, SRW, regAddr, regData, calcChecksum(SRW)};
    		Serial1.write(buf10, sizeof(buf10));
    		delay(50);			
    		
    		// enable PGA460 OWU communication mode
    		pinMode(COM_SEL, OUTPUT);  digitalWrite(COM_SEL, HIGH);
    	}
    	
    	//SPI setup (part II)
    	if (comm == 3)
    	{
    		// manually config chip select for debug (not used by PGA460)
    		pinMode(SPI_CS, OUTPUT); digitalWrite(SPI_CS, HIGH);
    		
    		// enable PGA460 SPI communication mode
    		pinMode(COM_SEL, OUTPUT);  digitalWrite(COM_SEL, HIGH);
    	}
    	
    	// Visibly show initilization status
    	//pinMode(GREEN_LED, OUTPUT);
    	if ((mode == 7) || (mode == 9))
    	{
    		// do not delay bus demo loop by blinking Green LED
    		//digitalWrite(RED_LED, LOW); // turn off LaunchPad's Red LED
    	}
    	else // blink LP's Green LED twice to indicate initialization is complete
    	{
    //		digitalWrite(GREEN_LED, HIGH);
    		for(int loops = 0; loops < 5; loops++)
    		{
    //			digitalWrite(GREEN_LED, HIGH); 
    			delay(200);
    //			digitalWrite(GREEN_LED, LOW);
    			delay(200);
    		}	
    	}
    	
    	return;
    }
    
    /*------------------------------------------------- defaultPGA460 -----
     |  Function defaultPGA460
     |
     |  Purpose:  Updates user EEPROM values, and performs bulk EEPROM write.
     |
     |  Parameters:
     |		xdcr (IN) -- updates user EEPROM based on predefined listing for a specific transducer.
     |			Modify existing case statements, or append additional case-statement for custom user EEPROM configurations.
     |			• 0 = Murata MA58MF14-7N
     |			• 1 = Murata MA40H1S-R
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::defaultPGA460(byte xdcr)
    {
    	switch (xdcr)
    	{
    		case 0: // Murata MA58MF14-7N
    		   USER_DATA1 = 0x00;
    		   USER_DATA2 = 0x00;
    		   USER_DATA3 = 0x00;
    		   USER_DATA4 = 0x00;
    		   USER_DATA5 = 0x00;
    		   USER_DATA6 = 0x00;
    		   USER_DATA7 = 0x00;
    		   USER_DATA8 = 0x00;
    		   USER_DATA9 = 0x00;
    		   USER_DATA10 = 0x00;
    		   USER_DATA11 = 0x00;
    		   USER_DATA12 = 0x00;
    		   USER_DATA13 = 0x00;
    		   USER_DATA14 = 0x00;
    		   USER_DATA15 = 0x00;
    		   USER_DATA16 = 0x00;
    		   USER_DATA17 = 0x00;
    		   USER_DATA18 = 0x00;
    		   USER_DATA19 = 0x00;
    		   USER_DATA20 = 0x00;
    		   TVGAIN0 = 0xAA;
    		   TVGAIN1 = 0xAA;
    		   TVGAIN2 = 0xAA;
    		   TVGAIN3 = 0x82;
    		   TVGAIN4 = 0x08;
    		   TVGAIN5 = 0x20;
    		   TVGAIN6 = 0x80;
    		   INIT_GAIN = 0x60;
    		   FREQUENCY  = 0x8F;
    		   DEADTIME = 0xA0;
    		   if (comm == 2)
    		   {
    				PULSE_P1 = 0x80 | 0x04;
    		   }
    		   else
    		   {
    				PULSE_P1 = 0x04;
    		   }
    		   PULSE_P2 = 0x10;
    		   CURR_LIM_P1 = 0x55;
    		   CURR_LIM_P2 = 0x55;
    		   REC_LENGTH = 0x19;
    		   FREQ_DIAG = 0x33;
    		   SAT_FDIAG_TH = 0xEE;
    		   FVOLT_DEC = 0x7C;
    		   DECPL_TEMP = 0x4F;
    		   DSP_SCALE = 0x00;
    		   TEMP_TRIM = 0x00;
    		   P1_GAIN_CTRL = 0x09;
    		   P2_GAIN_CTRL = 0x09;
    			break;		
    		case 1: // Murata MA40H1SR
    		   USER_DATA1 = 0x00;
    		   USER_DATA2 = 0x00;
    		   USER_DATA3 = 0x00;
    		   USER_DATA4 = 0x00;
    		   USER_DATA5 = 0x00;
    		   USER_DATA6 = 0x00;
    		   USER_DATA7 = 0x00;
    		   USER_DATA8 = 0x00;
    		   USER_DATA9 = 0x00;
    		   USER_DATA10 = 0x00;
    		   USER_DATA11 = 0x00;
    		   USER_DATA12 = 0x00;
    		   USER_DATA13 = 0x00;
    		   USER_DATA14 = 0x00;
    		   USER_DATA15 = 0x00;
    		   USER_DATA16 = 0x00;
    		   USER_DATA17 = 0x00;
    		   USER_DATA18 = 0x00;
    		   USER_DATA19 = 0x00;
    		   USER_DATA20 = 0x00;
    		   TVGAIN0 = 0xAA;
    		   TVGAIN1 = 0xAA;
    		   TVGAIN2 = 0xAA;
    		   TVGAIN3 = 0x51;
    		   TVGAIN4 = 0x45;
    		   TVGAIN5 = 0x14;
    		   TVGAIN6 = 0x50;
    		   INIT_GAIN = 0x54;
    		   FREQUENCY  = 0x32;
    		   DEADTIME = 0xA0;
    		   if (comm == 2)
    		   {
    				PULSE_P1 = 0x80 | 0x08;
    		   }
    		   else
    		   {
    				PULSE_P1 = 0x08;
    		   }
    		   PULSE_P2 = 0x10;
    		   CURR_LIM_P1 = 0x40;
    		   CURR_LIM_P2 = 0x40;
    		   REC_LENGTH = 0x19;
    		   FREQ_DIAG = 0x33;
    		   SAT_FDIAG_TH = 0xEE;
    		   FVOLT_DEC = 0x7C;
    		   DECPL_TEMP = 0x4F;
    		   DSP_SCALE = 0x00;
    		   TEMP_TRIM = 0x00;
    		   P1_GAIN_CTRL = 0x09;
    		   P2_GAIN_CTRL = 0x09;
    			break;
    		case 2: // user custom //DEBUG
    		{
    			USER_DATA1 = 0x00;
    		   USER_DATA2 = 0x00;
    		   USER_DATA3 = 0x00;
    		   USER_DATA4 = 0x00;
    		   USER_DATA5 = 0x00;
    		   USER_DATA6 = 0x00;
    		   USER_DATA7 = 0x00;
    		   USER_DATA8 = 0x00;
    		   USER_DATA9 = 0x00;
    		   USER_DATA10 = 0x00;
    		   USER_DATA11 = 0x00;
    		   USER_DATA12 = 0x00;
    		   USER_DATA13 = 0x00;
    		   USER_DATA14 = 0x00;
    		   USER_DATA15 = 0x00;
    		   USER_DATA16 = 0x00;
    		   USER_DATA17 = 0x00;
    		   USER_DATA18 = 0x00;
    		   USER_DATA19 = 0x00;
    		   USER_DATA20 = 0x00;
    		   TVGAIN0 = 0xAA;
    		   TVGAIN1 = 0xAA;
    		   TVGAIN2 = 0xAA;
    		   TVGAIN3 = 0x82;
    		   TVGAIN4 = 0x08;
    		   TVGAIN5 = 0x20;
    		   TVGAIN6 = 0x80;
    		   INIT_GAIN = 0x60;
    		   FREQUENCY  = 0x8F;
    		   DEADTIME = 0xA0;
    		   if (comm == 2)
    		   {
    				PULSE_P1 = 0x80 | 0x04;
    		   }
    		   else
    		   {
    				PULSE_P1 = 0x04;
    		   }
    		   PULSE_P2 = 0x50; //UART_ADDR=2
    		   CURR_LIM_P1 = 0x55;
    		   CURR_LIM_P2 = 0x55;
    		   REC_LENGTH = 0x19;
    		   FREQ_DIAG = 0x33;
    		   SAT_FDIAG_TH = 0xEE;
    		   FVOLT_DEC = 0x7C;
    		   DECPL_TEMP = 0x4F;
    		   DSP_SCALE = 0x00;
    		   TEMP_TRIM = 0x00;
    		   P1_GAIN_CTRL = 0x09;
    		   P2_GAIN_CTRL = 0x09;
    		   break;
    		}	
    		case 3: // user custom //DEBUG
    		{
    			USER_DATA1 = 0x00;
    		   USER_DATA2 = 0x00;
    		   USER_DATA3 = 0x00;
    		   USER_DATA4 = 0x00;
    		   USER_DATA5 = 0x00;
    		   USER_DATA6 = 0x00;
    		   USER_DATA7 = 0x00;
    		   USER_DATA8 = 0x00;
    		   USER_DATA9 = 0x00;
    		   USER_DATA10 = 0x00;
    		   USER_DATA11 = 0x00;
    		   USER_DATA12 = 0x00;
    		   USER_DATA13 = 0x00;
    		   USER_DATA14 = 0x00;
    		   USER_DATA15 = 0x00;
    		   USER_DATA16 = 0x00;
    		   USER_DATA17 = 0x00;
    		   USER_DATA18 = 0x00;
    		   USER_DATA19 = 0x00;
    		   USER_DATA20 = 0x00;
    		   TVGAIN0 = 0xAA;
    		   TVGAIN1 = 0xAA;
    		   TVGAIN2 = 0xAA;
    		   TVGAIN3 = 0x82;
    		   TVGAIN4 = 0x08;
    		   TVGAIN5 = 0x20;
    		   TVGAIN6 = 0x80;
    		   INIT_GAIN = 0x60;
    		   FREQUENCY  = 0x8F;
    		   DEADTIME = 0xA0;
    		   if (comm == 2)
    		   {
    				PULSE_P1 = 0x80 | 0x04;
    		   }
    		   else
    		   {
    				PULSE_P1 = 0x04;
    		   }
    		   PULSE_P2 = 0x70; //UART_ADDR=3
    		   CURR_LIM_P1 = 0x55;
    		   CURR_LIM_P2 = 0x55;
    		   REC_LENGTH = 0x19;
    		   FREQ_DIAG = 0x33;
    		   SAT_FDIAG_TH = 0xEE;
    		   FVOLT_DEC = 0x7C;
    		   DECPL_TEMP = 0x4F;
    		   DSP_SCALE = 0x00;
    		   TEMP_TRIM = 0x00;
    		   P1_GAIN_CTRL = 0x09;
    		   P2_GAIN_CTRL = 0x09;
    		   break;
    		}	
    		case 4: // user custom //DEBUG
    		{
    			USER_DATA1 = 0x00;
    		   USER_DATA2 = 0x00;
    		   USER_DATA3 = 0x00;
    		   USER_DATA4 = 0x00;
    		   USER_DATA5 = 0x00;
    		   USER_DATA6 = 0x00;
    		   USER_DATA7 = 0x00;
    		   USER_DATA8 = 0x00;
    		   USER_DATA9 = 0x00;
    		   USER_DATA10 = 0x00;
    		   USER_DATA11 = 0x00;
    		   USER_DATA12 = 0x00;
    		   USER_DATA13 = 0x00;
    		   USER_DATA14 = 0x00;
    		   USER_DATA15 = 0x00;
    		   USER_DATA16 = 0x00;
    		   USER_DATA17 = 0x00;
    		   USER_DATA18 = 0x00;
    		   USER_DATA19 = 0x00;
    		   USER_DATA20 = 0x00;
    		   TVGAIN0 = 0xAA;
    		   TVGAIN1 = 0xAA;
    		   TVGAIN2 = 0xAA;
    		   TVGAIN3 = 0x82;
    		   TVGAIN4 = 0x08;
    		   TVGAIN5 = 0x20;
    		   TVGAIN6 = 0x80;
    		   INIT_GAIN = 0x60;
    		   FREQUENCY  = 0x8F;
    		   DEADTIME = 0xA0;
    		   if (comm == 2)
    		   {
    				PULSE_P1 = 0x80 | 0x04;
    		   }
    		   else
    		   {
    				PULSE_P1 = 0x04;
    		   }
    		   PULSE_P2 = 0x90; //UART_ADDR=4
    		   CURR_LIM_P1 = 0x55;
    		   CURR_LIM_P2 = 0x55;
    		   REC_LENGTH = 0x19;
    		   FREQ_DIAG = 0x33;
    		   SAT_FDIAG_TH = 0xEE;
    		   FVOLT_DEC = 0x7C;
    		   DECPL_TEMP = 0x4F;
    		   DSP_SCALE = 0x00;
    		   TEMP_TRIM = 0x00;
    		   P1_GAIN_CTRL = 0x09;
    		   P2_GAIN_CTRL = 0x09;
    		   break;
    		}			
    		default: break;
    	}
    		
    		if ((comm == 0 || comm == 2 || comm ==3) && (comm !=6)) // USART or OWU mode and not busDemo6
    		{
    			byte buf12[46] = {syncByte, EEBW, USER_DATA1, USER_DATA2, USER_DATA3, USER_DATA4, USER_DATA5, USER_DATA6,
    				USER_DATA7, USER_DATA8, USER_DATA9, USER_DATA10, USER_DATA11, USER_DATA12, USER_DATA13, USER_DATA14, 
    				USER_DATA15,USER_DATA16,USER_DATA17,USER_DATA18,USER_DATA19,USER_DATA20,
    				TVGAIN0,TVGAIN1,TVGAIN2,TVGAIN3,TVGAIN4,TVGAIN5,TVGAIN6,INIT_GAIN,FREQUENCY,DEADTIME,
    				PULSE_P1,PULSE_P2,CURR_LIM_P1,CURR_LIM_P2,REC_LENGTH,FREQ_DIAG,SAT_FDIAG_TH,FVOLT_DEC,DECPL_TEMP,
    				DSP_SCALE,TEMP_TRIM,P1_GAIN_CTRL,P2_GAIN_CTRL,calcChecksum(EEBW)};
    		
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf12, sizeof(buf12)); // serial transmit master data for bulk EEPROM
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf12, sizeof(buf12));
    			}
    			delay(50);
    			
    			// Update targeted UART_ADDR to address defined in EEPROM bulk switch-case
    			byte uartAddrUpdate = (PULSE_P2 >> 5) & 0x07;
    			if (uartAddr != uartAddrUpdate)
    			{
    				// Update commands to account for new UART addr
    				  // Single Address
    				   P1BL = 0x00 + (uartAddrUpdate << 5);	   
    				   P2BL = 0x01 + (uartAddrUpdate << 5);
    				   P1LO = 0x02 + (uartAddrUpdate << 5);
    				   P2LO = 0x03 + (uartAddrUpdate << 5);
    				   TNLM = 0x04 + (uartAddrUpdate << 5);
    				   UMR = 0x05 + (uartAddrUpdate << 5);
    				   TNLR = 0x06 + (uartAddrUpdate << 5);
    				   TEDD = 0x07 + (uartAddrUpdate << 5);
    				   SD = 0x08 + (uartAddrUpdate << 5);
    				   SRR = 0x09 + (uartAddrUpdate << 5); 
    				   SRW = 0x0A + (uartAddrUpdate << 5);
    				   EEBR = 0x0B + (uartAddrUpdate << 5);
    				   EEBW = 0x0C + (uartAddrUpdate << 5);
    				   TVGBR = 0x0D + (uartAddrUpdate << 5);
    				   TVGBW = 0x0E + (uartAddrUpdate << 5);
    				   THRBR = 0x0F + (uartAddrUpdate << 5);
    				   THRBW = 0x10 + (uartAddrUpdate << 5);				
    			}
    			uartAddr = uartAddrUpdate;
    		}
    		else if (comm == 6)
    		{
    			return;
    		}
    		else if (comm == 1) // TCI mode
    		{			
    			tciIndexRW(13, true);	// TCI index 13 write		
    		}
    		else
    		{
    			//do nothing
    		}
    
    	return;
    }
    
    /*------------------------------------------------- initThresholds -----
     |  Function initThresholds
     |
     |  Purpose:  Updates threshold mapping for both presets, and performs bulk threshold write
     |
     |  Parameters:
     |		thr (IN) -- updates all threshold levels to a fixed level based on specific percentage of the maximum level. 
     |			All times are mid-code (1.4ms intervals).
     |			Modify existing case statements, or append additional case-statement for custom user threshold configurations.
     |			• 0 = 25% Levels 64 of 255
     |			• 1 = 50% Levels 128 of 255
     |			• 2 = 75% Levels 192 of 255
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::initThresholds(byte thr)
    {
    	switch (thr)
    	{
    		case 0: //25% Levels 64 of 255
    		   P1_THR_0 = 0x88;
    		   P1_THR_1 = 0x88;
    		   P1_THR_2 = 0x88;
    		   P1_THR_3 = 0x88;
    		   P1_THR_4 = 0x88;
    		   P1_THR_5 = 0x88;
    		   P1_THR_6 = 0x42;
    		   P1_THR_7 = 0x10;
    		   P1_THR_8 = 0x84;
    		   P1_THR_9 = 0x21;
    		   P1_THR_10 = 0x08;
    		   P1_THR_11 = 0x40;
    		   P1_THR_12 = 0x40;
    		   P1_THR_13 = 0x40;
    		   P1_THR_14 = 0x40;
    		   P1_THR_15 = 0x00;
    		   P2_THR_0 = 0x88;
    		   P2_THR_1 = 0x88;
    		   P2_THR_2 = 0x88;
    		   P2_THR_3 = 0x88;
    		   P2_THR_4 = 0x88;
    		   P2_THR_5 = 0x88;
    		   P2_THR_6 = 0x42;
    		   P2_THR_7 = 0x10;
    		   P2_THR_8 = 0x84;
    		   P2_THR_9 = 0x21;
    		   P2_THR_10 = 0x08;
    		   P2_THR_11 = 0x40;
    		   P2_THR_12 = 0x40;
    		   P2_THR_13 = 0x40;
    		   P2_THR_14 = 0x40;
    		   P2_THR_15 = 0x00;
    		break;
    		
    		case 1: //50% Level (midcode) 128 of 255
    		   P1_THR_0 = 0x88;
    		   P1_THR_1 = 0x88;
    		   P1_THR_2 = 0x88;
    		   P1_THR_3 = 0x88;
    		   P1_THR_4 = 0x88;
    		   P1_THR_5 = 0x88;
    		   P1_THR_6 = 0x84;
    		   P1_THR_7 = 0x21;
    		   P1_THR_8 = 0x08;
    		   P1_THR_9 = 0x42;
    		   P1_THR_10 = 0x10;
    		   P1_THR_11 = 0x80;
    		   P1_THR_12 = 0x80;
    		   P1_THR_13 = 0x80;
    		   P1_THR_14 = 0x80;
    		   P1_THR_15 = 0x00;
    		   P2_THR_0 = 0x88;
    		   P2_THR_1 = 0x88;
    		   P2_THR_2 = 0x88;
    		   P2_THR_3 = 0x88;
    		   P2_THR_4 = 0x88;
    		   P2_THR_5 = 0x88;
    		   P2_THR_6 = 0x84;
    		   P2_THR_7 = 0x21;
    		   P2_THR_8 = 0x08;
    		   P2_THR_9 = 0x42;
    		   P2_THR_10 = 0x10;
    		   P2_THR_11 = 0x80;
    		   P2_THR_12 = 0x80;
    		   P2_THR_13 = 0x80;
    		   P2_THR_14 = 0x80;
    		   P2_THR_15 = 0x00;		
    		break;
    		
    		case 2: //75% Levels 192 of 255
    		   P1_THR_0 = 0x88;
    		   P1_THR_1 = 0x88;
    		   P1_THR_2 = 0x88;
    		   P1_THR_3 = 0x88;
    		   P1_THR_4 = 0x88;
    		   P1_THR_5 = 0x88;
    		   P1_THR_6 = 0xC6;
    		   P1_THR_7 = 0x31;
    		   P1_THR_8 = 0x8C;
    		   P1_THR_9 = 0x63;
    		   P1_THR_10 = 0x18;
    		   P1_THR_11 = 0xC0;
    		   P1_THR_12 = 0xC0;
    		   P1_THR_13 = 0xC0;
    		   P1_THR_14 = 0xC0;
    		   P1_THR_15 = 0x00;
    		   P2_THR_0 = 0x88;
    		   P2_THR_1 = 0x88;
    		   P2_THR_2 = 0x88;
    		   P2_THR_3 = 0x88;
    		   P2_THR_4 = 0x88;
    		   P2_THR_5 = 0x88;
    		   P2_THR_6 = 0xC6;
    		   P2_THR_7 = 0x31;
    		   P2_THR_8 = 0x8C;
    		   P2_THR_9 = 0x63;
    		   P2_THR_10 = 0x18;
    		   P2_THR_11 = 0xC0;
    		   P2_THR_12 = 0xC0;
    		   P2_THR_13 = 0xC0;
    		   P2_THR_14 = 0xC0;
    		   P2_THR_15 = 0x00;
    		break;
    		
    		case 3: //Custom
    		   P1_THR_0 = 0x41;
    		   P1_THR_1 = 0x44;
    		   P1_THR_2 = 0x10;
    		   P1_THR_3 = 0x06;
    		   P1_THR_4 = 0x69;
    		   P1_THR_5 = 0x99;
    		   P1_THR_6 = 0xDD;
    		   P1_THR_7 = 0x4C;
    		   P1_THR_8 = 0x31;
    		   P1_THR_9 = 0x08;
    		   P1_THR_10 = 0x42;
    		   P1_THR_11 = 0x18;
    		   P1_THR_12 = 0x20;
    		   P1_THR_13 = 0x24;
    		   P1_THR_14 = 0x2A;
    		   P1_THR_15 = 0x00;
    		   P2_THR_0 = 0x41;
    		   P2_THR_1 = 0x44;
    		   P2_THR_2 = 0x10;
    		   P2_THR_3 = 0x06;
    		   P2_THR_4 = 0x09;
    		   P2_THR_5 = 0x99;
    		   P2_THR_6 = 0xDD;
    		   P2_THR_7 = 0x4C;
    		   P2_THR_8 = 0x31;
    		   P2_THR_9 = 0x08;
    		   P2_THR_10 = 0x42;
    		   P2_THR_11 = 0x24;
    		   P2_THR_12 = 0x30;
    		   P2_THR_13 = 0x36;
    		   P2_THR_14 = 0x3C;
    		   P2_THR_15 = 0x00;
    		break;
    		
    		default: break;
    	}
    				  
    	if ((comm == 0 || comm == 2 || comm==3) && (comm !=6)) 	// USART or OWU mode and not busDemo6
    	{
    		byte buf16[35] = {syncByte, THRBW, P1_THR_0, P1_THR_1, P1_THR_2, P1_THR_3, P1_THR_4, P1_THR_5, P1_THR_6,
    			  P1_THR_7, P1_THR_8, P1_THR_9, P1_THR_10, P1_THR_11, P1_THR_12, P1_THR_13, P1_THR_14, P1_THR_15,
    			  P2_THR_0, P2_THR_1, P2_THR_2, P2_THR_3, P2_THR_4, P2_THR_5, P2_THR_6, 
    			  P2_THR_7, P2_THR_8, P2_THR_9, P2_THR_10, P2_THR_11, P2_THR_12, P2_THR_13, P2_THR_14, P2_THR_15,
    			  calcChecksum(THRBW)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf16, sizeof(buf16)); // serial transmit master data for bulk threhsold
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf16, sizeof(buf16));
    		}
    		
    	}
    	else if(comm == 6)
    	{
    		return;
    	}
    	else if (comm == 1) // TCI mode
    	{
    		tciIndexRW(5, true); //TCI Threshold Preset 1 write
    		tciIndexRW(6, true); //TCI Threshold Preset 2 write
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	delay(100);
    	return;
    }
    
    /*------------------------------------------------- initTVG -----
     |  Function initTVG
     |
     |  Purpose:  Updates time varying gain (TVG) range and mapping, and performs bulk TVG write
     |
     |  Parameters:
     |		agr (IN) -- updates the analog gain range for the TVG.
     |			• 0 = 32-64dB
     |			• 1 = 46-78dB
     |			• 2 = 52-84dB
     |			• 3 = 58-90dB
     |		tvg (IN) -- updates all TVG levels to a fixed level based on specific percentage of the maximum level. 
     |			All times are mid-code (2.4ms intervals).
     |			Modify existing case statements, or append additional case-statement for custom user TVG configurations
     |			• 0 = 25% Levels of range
     |			• 1 = 50% Levels of range
     |			• 2 = 75% Levels of range
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::initTVG(byte agr, byte tvg)
    {
    	byte gain_range = 0x4F;
    	// set AFE gain range
    	switch (agr)
    	{
    		case 3: //58-90dB
    			gain_range =  0x0F;
    			break;		
    		case 2: //52-84dB
    			gain_range = 0x4F;
    			break;		
    		case 1: //46-78dB
    			gain_range = 0x8F;
    			break;
    		case 0: //32-64dB
    			gain_range = 0xCF;
    			break;
    		default: break;
    	}	
    
    	if ((comm == 0 || comm == 2 || comm == 3) && (comm !=6)) 	// USART or OWU mode and not busDemo6
    	{
    		regAddr = 0x26;
    		regData = gain_range;	
    		byte buf10[5] = {syncByte, SRW, regAddr, regData, calcChecksum(SRW)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf10, sizeof(buf10));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf10, sizeof(buf10));
    		}
    	}
    	else if(comm == 6)
    	{
    		return;
    	}
    	else if (comm == 1) // TCI mode
    	{
    		//TODO enable index 10 write
    		//tciIndexRW(10, true);
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	//Set fixed AFE gain value
    	switch (tvg)
    	{
    		case 0: //25% Level
    		   TVGAIN0 = 0x88;
    		   TVGAIN1 = 0x88;
    		   TVGAIN2 = 0x88;
    		   TVGAIN3 = 0x41;
    		   TVGAIN4 = 0x04;
    		   TVGAIN5 = 0x10;
    		   TVGAIN6 = 0x40;		
    		break;
    		
    		case 1: //50% Levels
    		   TVGAIN0 = 0x88;
    		   TVGAIN1 = 0x88;
    		   TVGAIN2 = 0x88;
    		   TVGAIN3 = 0x82;
    		   TVGAIN4 = 0x08;
    		   TVGAIN5 = 0x20;
    		   TVGAIN6 = 0x80;	
    		break;
    		
    		case 2: //75% Levels
    		   TVGAIN0 = 0x88;
    		   TVGAIN1 = 0x88;
    		   TVGAIN2 = 0x88;
    		   TVGAIN3 = 0xC3;
    		   TVGAIN4 = 0x0C;
    		   TVGAIN5 = 0x30;
    		   TVGAIN6 = 0xC0;	
    		break;
    		
    		default: break;
    	}	
    	
    	if ((comm == 0 || comm == 2 || comm == 3) && (comm !=6)) 	// USART or OWU mode and not busDemo6
    	{
    		byte buf14[10] = {syncByte, TVGBW, TVGAIN0, TVGAIN1, TVGAIN2, TVGAIN3, TVGAIN4, TVGAIN5, TVGAIN6, calcChecksum(TVGBW)};
    		
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf14, sizeof(buf14)); // serial transmit master data for bulk TVG
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf14, sizeof(buf14));
    		}
    	}
    	else if(comm == 6)
    	{
    		return;
    	}
    	else if (comm == 1) // TCI mode
    	{
    		tciIndexRW(8, true); //TCI bulk TVG write
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	return;
    }
    
    /*------------------------------------------------- ultrasonicCmd -----
     |  Function ultrasonicCmd
     |
     |  Purpose:  Issues a burst-and-listen or listen-only command based on the number of objects to be detected.
     |
     |  Parameters:
     |		cmd (IN) -- determines which preset command is run
     |			• 0 = Preset 1 Burst + Listen command
     |			• 1 = Preset 2 Burst + Listen command
     |			• 2 = Preset 1 Listen Only command
     |			• 3 = Preset 2 Listen Only command
     |			• 17 = Preset 1 Burst + Listen broadcast command
     |			• 18 = Preset 2 Burst + Listen broadcast command
     |			• 19 = Preset 1 Listen Only broadcast command
     |			• 20 = Preset 2 Listen Only broadcast command
     |		numObjUpdate (IN) -- PGA460 can capture time-of-flight, width, and amplitude for 1 to 8 objects. 
     |			TCI is limited to time-of-flight measurement data only.
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::ultrasonicCmd(byte cmd, byte numObjUpdate)
    {	
    	numObj = numObjUpdate; // number of objects to detect
    	byte bufCmd[4] = {syncByte, 0xFF, numObj, 0xFF}; // prepare bufCmd with 0xFF placeholders
    	
    	if (comm!=1)
    	{
    		memset(objTime, 0xFF, 8); // reset and idle-high TCI object buffer
    	}
    	
    	switch (cmd)
    	{
    		// SINGLE ADDRESS		
    		case 0: // Send Preset 1 Burst + Listen command
    		{			
    			bufCmd[1] = P1BL;
    			bufCmd[3] = calcChecksum(P1BL);
    			break;
    		}
    		case 1: // Send Preset 2 Burst + Listen command
    		{			
    			bufCmd[1] = P2BL;
    			bufCmd[3] = calcChecksum(P2BL);
    			break;
    		}	
    		case 2: // Send Preset 1 Listen Only command
    		{			
    			bufCmd[1] = P1LO;
    			bufCmd[3] = calcChecksum(P1LO);
    			break;
    		}
    		case 3: // Send Preset 2 Listen Only command
    		{			
    			bufCmd[1] = P2LO;
    			bufCmd[3] = calcChecksum(P2LO);
    			break;
    		}	
    		
    		// BROADCAST
    		case 17: // Send Preset 1 Burst + Listen Broadcast command
    		{			
    			bufCmd[1] = BC_P1BL;
    			bufCmd[3] = calcChecksum(BC_P1BL);
    			break;
    		}
    		case 18: // Send Preset 2 Burst + Listen Broadcast command
    		{			
    			bufCmd[1] = BC_P2BL;
    			bufCmd[3] = calcChecksum(BC_P2BL);
    			break;
    		}	
    		case 19: // Send Preset 1 Listen Only Broadcast command
    		{			
    			bufCmd[1] = BC_P1LO;
    			bufCmd[3] = calcChecksum(BC_P1LO);
    			break;
    		}
    		case 20: // Send Preset 2 Listen Only Broadcast command
    		{			
    			bufCmd[1] = BC_P2LO;
    			bufCmd[3] = calcChecksum(BC_P2LO);
    			break;
    		}		
    		
    		default: return;	
    	}		
    	
    	if(comm !=1 ) // USART or OWU modes only
    	{
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(bufCmd, sizeof(bufCmd)); // serial transmit master data to initiate burst and/or listen command
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(bufCmd, sizeof(bufCmd));
    		}
    	}
    	else if (comm == 1) // TCI mode
    	{
    		tciCommand(cmd); // send preset 1 or 2 burst-and-listen or listen-only command
    		pga460::tciRecord(numObj); // log up to eight TCI object toggles
    	}	
    	else
    	{
    		//do nothing
    	}
    	
    	delay(70); // maximum record length is 65ms, so delay with margin
    	return;
    }
    
    /*------------------------------------------------- pullUltrasonicMeasResult -----
     |  Function pullUltrasonicMeasResult
     |
     |  Purpose:  Read the ultrasonic measurement result data based on the last busrt and/or listen command issued.
     |	Only applicable to UART and OWU modes.
     |
     |  Parameters:
     |		busDemo (IN) -- When true, do not print error message for a failed reading when running bus demo
     |
     |  Returns:  If measurement data successfully read, return true.
     *-------------------------------------------------------------------*/
    bool pga460::pullUltrasonicMeasResult(bool busDemo)
    {
    	if (comm != 1) // USART or OWU mode
    	{
    		pga460SerialFlush();
    		
    		memset(ultraMeasResult, 0, sizeof(ultraMeasResult));
    		
    		if (comm == 2)
    		{
    		   owuShift = 2; // OWU receive buffer offset to ignore transmitted data
    		}
    		
    		byte buf5[3] = {syncByte, UMR, calcChecksum(UMR)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf5, sizeof(buf5)); //serial transmit master data to read ultrasonic measurement results
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf5, sizeof(buf5));
    		}
    		
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			starttime = millis();
    			while ( (Serial1.available()<(5+owuShift)) && ((millis() - starttime) < MAX_MILLIS_TO_WAIT) )
    			{      
    				// wait in this loop until we either get +5 bytes of data, or 0.25 seconds have gone by
    			}
    			
    			if((Serial1.available() < (5+owuShift)))
    			{
    				if (busDemo == false)
    				{
    					// the data didn't come in - handle the problem here
    					Serial.println("ERROR - Did not receive measurement results!");
    				}
    				return false;
    			}
    			else
    			{
    				for(int n=0; n<((2+(numObj*4))+owuShift); n++)
    				{			
    				   ultraMeasResult[n] = Serial1.read();
    				   delay(1);		   
    				}
    
    				if (comm == 2) // OWU mode only
    				{
    					//rearrange array for OWU UMR results
    					for(int n=0; n<(2+(numObj*4)); n++)
    					{
    						ultraMeasResult[n+1] = ultraMeasResult[n+owuShift]; //element 0 skipped due to no diagnostic field returned
    					}
    				}				
    			}
    		}
    		if (comm == 3)
    		{
    			// MOSI transmit 0xFF to pull MISO return data
    			spiMosiIdle(numObj*4+1);
    			
    			// copy MISO global array data to local array based on number of objects
    			for(int n=0; n<((2+(numObj*4))+owuShift); n++)
    			{			
    			   ultraMeasResult[n+1] = misoBuf[n];	   
    			}
    		}
    	}
    	else
    	{
    		//do nothing
    	}
    	return true;
    }
    
    /*------------------------------------------------- printUltrasonicMeasResult -----
     |  Function printUltrasonicMeasResult
     |
     |  Purpose:  Converts time-of-flight readout to distance in meters. 
     |		Width and amplitude data only available in UART or OWU mode.
     |
     |  Parameters:
     |		umr (IN) -- Ultrasonic measurement result look-up selector:
     |				Distance (m)	Width	Amplitude
     |				--------------------------------
     |			Obj1		0		1		2
     |			Obj2		3		4		5
     |			Obj3		6		7		8
     |			Obj4		9		10		11
     |			Obj5		12		13		14
     |			Obj6		15		16		17
     |			Obj7		18		19		20
     |			Obj8		21		22		23
     |
     |  Returns:  double representation of distance (m), width (us), or amplitude (8-bit)
     *-------------------------------------------------------------------*/
    double pga460::printUltrasonicMeasResult(byte umr)
    {
    	int speedSound = 343; // speed of sound in air at room temperature
    	pga460::printUltrasonicMeasResultExt(umr, speedSound);
    }
    byte pga460::printUltrasonicMeasResultRaw(byte umr)
    {
    	return ultraMeasResult[umr];
    }
    double pga460::printUltrasonicMeasResultExt(byte umr, int speedSound)
    {
    	double objReturn = 0;
    	double digitalDelay = 0; // TODO: compensates the burst time calculated as number_of_pulses/frequency.
    	uint16_t objDist = 0;
    	uint16_t objWidth = 0;
    	uint16_t objAmp = 0;
    	
    	switch (umr)
    	{
    		case 0: //Obj1 Distance (m)
    		{
    			objDist = (ultraMeasResult[1]<<8) + ultraMeasResult[2];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 1: //Obj1 Width (us)
    		{
    			objWidth = ultraMeasResult[3];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 2: //Obj1 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[4];
    			objReturn= objAmp;
    			break;
    		}
    		
    		case 3: //Obj2 Distance (m)
    		{
    			objDist = (ultraMeasResult[5]<<8) + ultraMeasResult[6];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 4: //Obj2 Width (us)
    		{
    			objWidth = ultraMeasResult[7];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 5: //Obj2 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[8];
    			objReturn= objAmp;
    			break;
    		}
    		
    		case 6: //Obj3 Distance (m)
    		{
    			objDist = (ultraMeasResult[9]<<8) + ultraMeasResult[10];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 7: //Obj3 Width (us)
    		{
    			objWidth = ultraMeasResult[11];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 8: //Obj3 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[12];
    			objReturn= objAmp;
    			break;
    		}
    		case 9: //Obj4 Distance (m)
    		{
    			objDist = (ultraMeasResult[13]<<8) + ultraMeasResult[14];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 10: //Obj4 Width (us)
    		{
    			objWidth = ultraMeasResult[15];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 11: //Obj4 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[16];
    			objReturn= objAmp;
    			break;
    		}
    		case 12: //Obj5 Distance (m)
    		{
    			objDist = (ultraMeasResult[17]<<8) + ultraMeasResult[18];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 13: //Obj5 Width (us)
    		{
    			objWidth = ultraMeasResult[19];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 14: //Obj5 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[20];
    			objReturn= objAmp;
    			break;
    		}
    		case 15: //Obj6 Distance (m)
    		{
    			objDist = (ultraMeasResult[21]<<8) + ultraMeasResult[22];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 16: //Obj6 Width (us)
    		{
    			objWidth = ultraMeasResult[23];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 17: //Obj6 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[24];
    			objReturn= objAmp;
    			break;
    		}
    		case 18: //Obj7 Distance (m)
    		{
    			objDist = (ultraMeasResult[25]<<8) + ultraMeasResult[26];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 19: //Obj7 Width (us)
    		{
    			objWidth = ultraMeasResult[27];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 20: //Obj7 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[28];
    			objReturn= objAmp;
    			break;
    		}
    		case 21: //Obj8 Distance (m)
    		{
    			objDist = (ultraMeasResult[29]<<8) + ultraMeasResult[30];
    			objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
    			break;
    		}
    		case 22: //Obj8 Width (us)
    		{
    			objWidth = ultraMeasResult[31];
    			objReturn= objWidth * 16;
    			break;
    		}
    		case 23: //Obj8 Peak Amplitude
    		{
    			objAmp = ultraMeasResult[32];
    			objReturn= objAmp;
    			break;
    		}		
    		default: Serial.println("ERROR - Invalid object result!"); break;
    	}	
    	return objReturn;
    }
    
    /*------------------------------------------------- runEchoDataDump -----
     |  Function runEchoDataDump
     |
     |  Purpose:  Runs a preset 1 or 2 burst and or listen command to capture 128 bytes of echo data dump.
     |		Toggle echo data dump enable bit to enable/disable echo data dump mode.
     |
     |  Parameters:
     |		preset (IN) -- determines which preset command is run:
     |			• 0 = Preset 1 Burst + Listen command
     |			• 1 = Preset 2 Burst + Listen command
     |			• 2 = Preset 1 Listen Only command
     |			• 3 = Preset 2 Listen Only command
     |			• 17 = Preset 1 Burst + Listen broadcast command
     |			• 18 = Preset 2 Burst + Listen broadcast command
     |			• 19 = Preset 1 Listen Only broadcast command
     |			• 20 = Preset 2 Listen Only broadcast command
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::runEchoDataDump(byte preset)
    {
    	if (comm != 1) // USART or OWU mode
    	{	
    		// enable Echo Data Dump bit
    		regAddr = 0x40;
    		regData = 0x80;
    		byte writeType = SRW; // default to single address register write (cmd10)
    		if(preset>16) // update to broadcast register write if broadcast TOF preset command given
    		{
    			writeType = BC_RW; // cmd22
    		}
    		
    		byte buf10[5] = {syncByte, writeType, regAddr, regData, calcChecksum(writeType)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			pga460SerialFlush();
    			Serial1.write(buf10, sizeof(buf10));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf10, sizeof(buf10));
    		}
    		delay(10);
    		
    		
    		// run preset 1 or 2 burst and or listen command
    		pga460::ultrasonicCmd(preset, 1);	
    
    		// disbale Echo Data Dump bit
    		regData = 0x00;
    		buf10[3] = regData;
    		buf10[4] = calcChecksum(writeType);
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf10, sizeof(buf10));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf10, sizeof(buf10));
    		}		
    	}
    	else if (comm == 1) // TCI mode
    	{
    		EE_CNTRL = 0x80; 		// enable echo data dump 
    		tciIndexRW(11, true); 	// write to index 11
    		
    		delay(10);
    		tciCommand(preset); 	// run burst+listen command
    		delay(100);				// delay for maximum record time length with margin
    		
    		EE_CNTRL = 0x00; 		// disable echo data dump
    		tciIndexRW(11, true); 	// write to index 11		
    		delay(10);			
    	}
    	else
    	{
    		//do nothing
    	}
    	return;
    }
    
    /*------------------------------------------------- pullEchoDataDump -----
     |  Function pullEchoDataDump
     |
     |  Purpose:  Read out 128 bytes of echo data dump (EDD) from latest burst and or listen command. 
     |		For UART and OWU, readout individual echo data dump register values, instead in bulk.
     |		For TCI, perform index 12 read of all echo data dump values in bulk.
     |
     |  Parameters:
     |		element (IN) -- element from the 128 byte EDD memory
     |
     |  Returns:  byte representation of EDD element value
     *-------------------------------------------------------------------*/
    byte pga460::pullEchoDataDump(byte element)
    {
    	if (comm != 1 && comm != 3) // UART or OWU mode
    	{
    		if (element == 0)
    		{
    			byte temp = 0;
    			pga460SerialFlush();
    			
    			if (comm == 2)
    			{
    				owuShift = 2; // OWU receive buffer offset to ignore transmitted data
    			}
    			else
    			{
    				owuShift = 0;
    			}	
    			
    			regAddr = 0x80; // start of EDD memory
    			byte buf9[4] = {syncByte, SRR, regAddr, calcChecksum(SRR)}; 
    			Serial1.write(buf9, sizeof(buf9)); // read first byte of EDD memory		
    			
    			for(int m=0; m<129; m++) // loop readout by iterating through EDD address range
    			{
    			   buf9[2] = regAddr;
    			   buf9[3] = calcChecksum(SRR);
    			   Serial1.write(buf9, sizeof(buf9));
    			   delay(30);	 
    			   
    			   for(int n=0; n<(128+owuShift); n++)
    			   {
    				   if(n==(1 + owuShift))
    				   {
    						echoDataDump[m] = Serial1.read();						
    				   }
    				   else
    				   {
    					   temp = Serial1.read();
    				   }
    			   }
    			   regAddr++;
    			}			
    		}
    		return echoDataDump[element];	
    	}
    	else if (comm == 1) // TCI
    	{
    		if (element == 0)
    		{
    			tciIndexRW(12, false); //only run when first calling this function to read out the entire EDD to the receive buffer
    			delay (500); // wait until EDD read out is completed with margin
    		}		
    		delay(10);
    		return bufRecv[element];
    	}
    	else if (comm == 3) // SPI
    	{
    		// run read bulk transducer echo data dump command on first iteration
    		if (element == 0)
    		{
    			byte buf7[3] = {syncByte, TEDD, calcChecksum(TEDD)};
    			spiTransfer(buf7, sizeof(buf7));
    			// MOSI transmit 0xFF to pull MISO return data
    			spiMosiIdle(129);
    			//// copy MISO global array data to local array based on number of objects
    			//for(int n=0; n<129; n++)
    			//{			
    			//   localArry[n] = misoBuf[n];	   
    			//}
    		}
    		return misoBuf[element];
    	}
    	else
    	{
    		//do nothing
    	}
    	return 0xFF;
    }
    
    /*------------------------------------------------- pullEchoDataDumpBulk -----
     |  Function pullEchoDataDumpBulk
     |
     |  Purpose:  Bulk read out 128 bytes of echo data dump (EDD) from latest burst and or listen command. 
     |		For UART and OWU, readout bulk echo data dump register values.
     |		For TCI, perform index 12 read of all echo data dump values in bulk.
     |
     |  Parameters:
     |		none
     |
     |  Returns:  comma delimited string of all EDD values
     *-------------------------------------------------------------------*/
    String pga460::pullEchoDataDumpBulk()
    {
    	String bulkString = "";
    	if (comm != 1 && comm != 3) // UART or OWU mode
    	{
    		byte temp = 0;
    		pga460SerialFlush();
    		
    		if (comm == 2)
    		{
    			owuShift = 2; // OWU receive buffer offset to ignore transmitted data
    		}
    		else
    		{
    			owuShift = 0;
    		}	
    		
    		byte buf7[3] = {syncByte, TEDD, calcChecksum(TEDD)}; 
    		Serial1.write(buf7, sizeof(buf7)); // respond bulk EDD command			
    		byte eddBulk[130];
    		Serial1.readBytes((char *)eddBulk,130);
    		
    		if(eddBulk[0] != 0) // if diagnostic field is non-zero
    		{			
    			for(int n=1+owuShift; n<(129+owuShift); n++)
    			{			
    			   bulkString = bulkString + "," + eddBulk[n];	   
    			}
    		}
    		else
    		{
    			// the data didn't come in - handle the problem here
    			Serial.print("ERROR - Did not receive echo data dump! ");	
    			for(int n=1+owuShift; n<(129+owuShift); n++)
    			{			
    			   bulkString = bulkString + "," + eddBulk[n];		   
    			}		
    		}
    		return bulkString;	
    	}
    	else if (comm == 1) // TCI
    	{		
    		tciIndexRW(12, false); //only run when first calling this function to read out the entire EDD to the receive buffer
    		delay (500); // wait until EDD read out is completed with margin
    		delay(10);
    		for(int n=1; n<129; n++)
    		{			
    		   bulkString = bulkString + "," + bufRecv[n];		   
    		}
    		return bulkString;	
    	}
    	else if (comm == 3) // SPI
    	{
    		// run read bulk transducer echo data dump command on first iteration
    		byte buf7[3] = {syncByte, TEDD, calcChecksum(TEDD)};
    		spiTransfer(buf7, sizeof(buf7));
    		// MOSI transmit 0xFF to pull MISO return data
    		spiMosiIdle(129);
    		for(int n=0; n<128; n++)
    		{			
    		   bulkString = bulkString + "," + misoBuf[n];		   
    		}
    		return bulkString;
    	}
    	else
    	{
    		//do nothing
    	}
    	return "ERROR - pullEchoDataDumpBulk";
    }
    
    /*------------------------------------------------- runDiagnostics -----
     |  Function runDiagnostics
     |
     |  Purpose:  Runs a burst+listen command to capture frequency, decay, and voltage diagnostic.
     |		Runs a listen-only command to capture noise level.
     |		Captures die temperature of PGA460 device.
     |		Converts raw diagnostics to comprehensive units
     |
     |  Parameters:
     |		run (IN) -- issue a preset 1 burst-and-listen command
     |		diag (IN) -- diagnostic value to return:
     |			• 0 = frequency diagnostic (kHz)
     |			• 1 = decay period diagnostic (us)
     |			• 2 = die temperature (degC)
     |			• 3 = noise level (8bit)
     |
     |  Returns:  double representation of last captured diagnostic
     *-------------------------------------------------------------------*/
    double pga460::runDiagnostics(byte run, byte diag)
    {
    	double diagReturn = 0;
    	pga460SerialFlush();
    	int elementOffset = 0; //Only non-zero for OWU mode.
    	int owuShiftSysDiag = 0; // Only non-zero for OWU mode.
    	
    	if (comm != 1) // USART and OWU
    	{
    		if (comm == 2)
    		{
    			owuShift = 2; // OWU receive buffer offset to ignore transmitted data
    			owuShiftSysDiag = 1;
    		}
    			
    		if (run == 1) // issue  P1 burst+listen, and run system diagnostics command to get latest results
    		{
    			// run burst+listen command at least once for proper diagnostic analysis
    			pga460::ultrasonicCmd(0, 1);	// always run preset 1 (short distance) burst+listen for 1 object for system diagnostic
    			
    			
    			delay(100); // record time length maximum of 65ms, so add margin
    			pga460SerialFlush();
    			
    			byte buf8[3] = {syncByte, SD, calcChecksum(SD)};
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf8, sizeof(buf8)); //serial transmit master data to read system diagnostic results			
    				
    				starttime = millis();
    				while ( (Serial1.available()<(4+owuShift-owuShiftSysDiag)) && ((millis() - starttime) < MAX_MILLIS_TO_WAIT) )
    				{      
    					// wait in this loop until we either get +4 bytes of data or 0.25 seconds have gone by
    				}
    				if(Serial1.available() < (4+owuShift-owuShiftSysDiag))
    				{
    					// the data didn't come in - handle the problem here
    					Serial.println("ERROR - Did not receive system diagnostics!");
    				}
    				else
    				{
    					for(int n=0; n<(4+owuShift-owuShiftSysDiag); n++)
    					{
    					   diagMeasResult[n] = Serial1.read();
    					}
    				}
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf8, sizeof(buf8));
    				// MOSI transmit 0xFF to pull MISO return data
    				spiMosiIdle(3);
    				for(int n=0; n<2; n++)
    				{
    				   diagMeasResult[n] = misoBuf[n];
    				}
    			}
    		}
    		
    		if (diag == 2) //run temperature measurement
    		{
    			tempOrNoise = 0; // temp meas
    			byte buf4[4] = {syncByte, TNLM, tempOrNoise, calcChecksum(TNLM)}; 
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf4, sizeof(buf4)); //serial transmit master data to run temp measurement
    				delay(10);
    				pga460SerialFlush();
    				delay(10);
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf4, sizeof(buf4));
    			}
    			
    			byte buf6[3] = {syncByte, TNLR, calcChecksum(TNLR)};
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf6, sizeof(buf6)); //serial transmit master data to read temperature and noise results
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf6, sizeof(buf6));
    				spiMosiIdle(3);
    			}
    			
    			delay(100);		
    		}
    			
    		if (diag == 3) // run noise level meas
    		{
    			tempOrNoise = 1; // noise meas
    			byte buf4[4] = {syncByte, TNLM, tempOrNoise, calcChecksum(TNLM)};
    			
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf4, sizeof(buf4)); //serial transmit master data to run noise level measurement (requires at least 8.2ms of post-delay)
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf4, sizeof(buf4));
    			}
    			
    			delay(10);
    			pga460SerialFlush();
    			delay(10);
    			
    			byte buf6[3] = {syncByte, TNLR, calcChecksum(TNLR)}; //serial transmit master data to read temperature and noise results
    			if (comm == 0 || comm == 2) // UART or OWU mode
    			{
    				Serial1.write(buf6, sizeof(buf6));
    			}
    			if (comm == 3) // SPI mode
    			{
    				spiTransfer(buf6, sizeof(buf6));
    				spiMosiIdle(3);
    			}
    			
    			delay(100);
    		}
    			
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{	
    			if (diag == 2 || diag == 3) // pull temp and noise level results
    			{
    				starttime = millis();
    				while ( (Serial1.available()<(4+owuShift-owuShiftSysDiag)) && ((millis() - starttime) < MAX_MILLIS_TO_WAIT) )
    				{      
    					// wait in this loop until we either get +4 bytes of data or 0.25 seconds have gone by
    				}
    				
    				if(Serial1.available() < (4+owuShift-owuShiftSysDiag))
    				{
    					// the data didn't come in - handle the problem here
    					Serial.println("ERROR - Did not receive temp/noise!");
    				}
    				else
    				{
    					for(int n=0; n<(4+owuShift-owuShiftSysDiag); n++)
    					{
    					   tempNoiseMeasResult[n] = Serial1.read();
    					}
    							
    				}
    			}
    			elementOffset = owuShift-owuShiftSysDiag; // OWU only
    		}
    		if (comm == 3) // SPI mode
    		{
    			for(int n=0; n<2; n++)
    			{
    			   tempNoiseMeasResult[n] = misoBuf[n];
    			}
    		}
    		
    		// if SPI mode, do not apply array offset
    		if (comm == 3)
    		{
    			elementOffset = -1;
    		}
    		else
    		{
    			elementOffset = owuShift-owuShiftSysDiag; // OWU only
    		}
    			
    	}
    	else if (comm == 1) //TCI
    	{
    		if (run == true)
    		{	
    			delay(10);	
    			tciCommand(6); // run noise level measurement command			
    			delay(15);
    			tciCommand(1); //run preset 2 burst+listen command
    			delay(100);	// maximum record length is 65ms, so wait with margin
    
    
    			tciIndexRW(1, false); //read index1	
    			delay(10);
    
    			for(int n=1; n<4; n++)
    			{
    			   diagMeasResult[n] = bufRecv[n-1];
    			}			
    			tempNoiseMeasResult[2] = diagMeasResult[3]; //clone temperature result to element 2			
    			
    			delay(10);
    			tciCommand(5); // run temperature measurement command
    			delay(10);
    			
    			tciIndexRW(0,false); //read index0
    			delay(10);			
    			
    			tempNoiseMeasResult[1] = bufRecv[0]; //store temp readout to element 1
    		}
    		elementOffset = 0; // no offset required fot TCI
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	delay(100);
    		
    	switch (diag)
    	{
    		case 0: // convert to transducer frequency in kHz
    			{
    				diagReturn = (1 / (diagMeasResult[1+elementOffset] * 0.0000005)) / 1000;
    			}
    			break;
    		case 1: // convert to decay period time in us
    			{
    				diagReturn = diagMeasResult[2+elementOffset] * 16;
    			}
    			break;
    		case 2: //convert to temperature in degC
    			{
    				diagReturn = (tempNoiseMeasResult[1+elementOffset] - 64) / 1.5;
    			}
    			break;
    		case 3: //noise floor level
    			{
    				diagReturn = tempNoiseMeasResult[2+elementOffset];
    			}
    			break;
    		default: break;
    	}
    	
    	return diagReturn;
    }
    
    /*------------------------------------------------- burnEEPROM -----
     |  Function burnEEPROM
     |
     |  Purpose:  Burns the EEPROM to preserve the working/shadow register values to EEPROM after power
     |		cycling the PGA460 device. Returns EE_PGRM_OK bit to determine if EEPROM burn was successful.
     |
     |  Parameters:
     |		none
     |
     |  Returns:  bool representation of EEPROM program success
     *-------------------------------------------------------------------*/
    bool pga460::burnEEPROM()
    {
    	byte burnStat = 0;
    	byte temp = 0;
    	bool burnSuccess = false;
    	
    	if (comm != 1 || comm != 3)
    	{	
    			
    		// Write "0xD" to EE_UNLCK to unlock EEPROM, and '0' to EEPRGM bit at EE_CNTRL register
    		regAddr = 0x40; //EE_CNTRL
    		regData = 0x68;
    		byte buf10[5] = {syncByte, SRW, regAddr, regData, calcChecksum(SRW)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf10, sizeof(buf10));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf10, sizeof(buf10));
    		}
    		
    		delay(1);
    		
    		// Write "0xD" to EE_UNLCK to unlock EEPROM, and '1' to EEPRGM bit at EE_CNTRL register
    		regAddr = 0x40; //EE_CNTRL
    		regData = 0x69;
    		buf10[2] = regAddr;
    		buf10[3] = regData;
    		buf10[4] = calcChecksum(SRW);
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf10, sizeof(buf10));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf10, sizeof(buf10));
    		}
    		delay(1000);
    		
    		
    		// Read back EEPROM program status
    		if (comm == 2)
    		{
    			owuShift = 1; // OWU receive buffer offset to ignore transmitted data
    		}	
    		pga460SerialFlush();
    		regAddr = 0x40; //EE_CNTRL
    		byte buf9[4] = {syncByte, SRR, regAddr, calcChecksum(SRR)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf9, sizeof(buf9));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf9, sizeof(buf9));
    		}
    		delay(10);
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			for(int n=0; n<3; n++)
    			{
    			   if(n==1-owuShift)
    			   {
    					burnStat = Serial1.read(); // store EE_CNTRL data
    			   }
    			   else
    			   {
    				   temp = Serial1.read();
    			   }
    			}
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiMosiIdle(3);
    			burnStat = misoBuf[1];
    		}
    	}
    	else if (comm == 1) // TCI mode
    	{
    		EE_CNTRL = 0x68;
    		tciIndexRW(11, true); 	// write to index 11 to EE_UNLCK to unlock EEPROM, and '0' to EEPRGM bit at EE_CNTRL register
    		delay(1); 				// immediately send the same UART or TCI command with the EEPRGM bit set to '1'.
    		EE_CNTRL = 0x69;
    		tciIndexRW(11, true); 	// write to index 11 to EE_UNLCK to unlock EEPROM, and '1' to EEPRGM bit at EE_CNTRL register
    		delay(1000);
    		tciIndexRW(11, false);	// read back index 11 to review EE_PGRM_OK bit	
    		burnStat = bufRecv[0];		
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	if((burnStat & 0x04) == 0x04){burnSuccess = true;} // check if EE_PGRM_OK bit is '1'
    	
    	return burnSuccess;
    }
    
    /*------------------------------------------------- broadcast -----
     |  Function broadcast
     |
     |  Purpose:  Send a broadcast command to bulk write the user EEPROM, TVG, and/or Threshold values for all devices, regardless of UART_ADDR.
     |		Placehold for user EEPROM broadcast available. Note, all devices will update to the same UART_ADDR in user EEPROM broadcast command.
     |		This function is not applicable to TCI mode.
     |
     |  Parameters:
     |		eeBulk (IN) -- if true, broadcast user EEPROM
     |		tvgBulk (IN) -- if true, broadcast TVG
     |		thrBulk (IN) -- if true, broadcast Threshold
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::broadcast(bool eeBulk, bool tvgBulk, bool thrBulk)
    {
    
    	// TVG broadcast command:
    	if (tvgBulk == true)
    	{
    		byte buf24[10] = {syncByte, BC_TVGBW, TVGAIN0, TVGAIN1, TVGAIN2, TVGAIN3, TVGAIN4, TVGAIN5, TVGAIN6, calcChecksum(BC_TVGBW)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf24, sizeof(buf24));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf24, sizeof(buf24));
    		}		
    		delay(10);
    	}
    	
    	// Threshold broadcast command:
    	if (thrBulk == true)
    	{
    		byte buf25[35] = {syncByte, BC_THRBW, P1_THR_0, P1_THR_1, P1_THR_2, P1_THR_3, P1_THR_4, P1_THR_5, P1_THR_6,
    		  P1_THR_7, P1_THR_8, P1_THR_9, P1_THR_10, P1_THR_11, P1_THR_12, P1_THR_13, P1_THR_14, P1_THR_15,
    		  P2_THR_0, P2_THR_1, P2_THR_2, P2_THR_3, P2_THR_4, P2_THR_5, P2_THR_6, 
    		  P2_THR_7, P2_THR_8, P2_THR_9, P2_THR_10, P2_THR_11, P2_THR_12, P2_THR_13, P2_THR_14, P2_THR_15,
    		  calcChecksum(BC_THRBW)};
    
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf25, sizeof(buf25));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf25, sizeof(buf25));
    		}	
    		delay(10);		
    	}
    	
    	// User EEPROM broadcast command (placeholder):
    	if (eeBulk == true)
    	{
    		byte buf23[46] = {syncByte, BC_EEBW, USER_DATA1, USER_DATA2, USER_DATA3, USER_DATA4, USER_DATA5, USER_DATA6,
    			USER_DATA7, USER_DATA8, USER_DATA9, USER_DATA10, USER_DATA11, USER_DATA12, USER_DATA13, USER_DATA14, 
    			USER_DATA15,USER_DATA16,USER_DATA17,USER_DATA18,USER_DATA19,USER_DATA20,
    			TVGAIN0,TVGAIN1,TVGAIN2,TVGAIN3,TVGAIN4,TVGAIN5,TVGAIN6,INIT_GAIN,FREQUENCY,DEADTIME,
    			PULSE_P1,PULSE_P2,CURR_LIM_P1,CURR_LIM_P2,REC_LENGTH,FREQ_DIAG,SAT_FDIAG_TH,FVOLT_DEC,DECPL_TEMP,
    			DSP_SCALE,TEMP_TRIM,P1_GAIN_CTRL,P2_GAIN_CTRL,calcChecksum(BC_EEBW)};
    		
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf23, sizeof(buf23));
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf23, sizeof(buf23));
    		}	
    		delay(50);
    	}
    	
    	return;
    }
    
    
    /*------------------------------------------------- calcChecksum -----
     |  Function calcChecksum
     |
     |  Purpose:  Calculates the UART checksum value based on the selected command and the user EERPOM values associated with the command
     |		This function is not applicable to TCI mode. 
     |
     |  Parameters:
     |		cmd (IN) -- the UART command for which the checksum should be calculated for
     |
     |  Returns: byte representation of calculated checksum value
     *-------------------------------------------------------------------*/
    byte pga460::calcChecksum(byte cmd)
    {
    	int checksumLoops = 0;
    	
    	cmd = cmd & 0x001F; // zero-mask command address of cmd to select correct switch-case statement
    	
    	switch(cmd)
    	{
    		case 0 : //P1BL
    		case 1 : //P2BL
    		case 2 : //P1LO
    		case 3 : //P2LO
    		case 17 : //BC_P1BL
    		case 18 : //BC_P2BL
    		case 19 : //BC_P1LO
    		case 20 : //BC_P2LO
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = numObj;
    			checksumLoops = 2;
    		break;
    		case 4 : //TNLM
    		case 21 : //TNLM
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = tempOrNoise;
    			checksumLoops = 2;
    		break;
    		case 5 : //UMR
    		case 6 : //TNLR
    		case 7 : //TEDD
    		case 8 : //SD
    		case 11 : //EEBR
    		case 13 : //TVGBR
    		case 15 : //THRBR
    			ChecksumInput[0] = cmd;
    			checksumLoops = 1;
    		break;
    		case 9 : //RR
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = regAddr;
    			checksumLoops = 2;
    		break;
    		case 10 : //RW
    		case 22 : //BC_RW
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = regAddr;
    			ChecksumInput[2] = regData;
    			checksumLoops = 3;
    		break;
    		case 14 : //TVGBW
    		case 24 : //BC_TVGBW
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = TVGAIN0;
    			ChecksumInput[2] = TVGAIN1;
    			ChecksumInput[3] = TVGAIN2;
    			ChecksumInput[4] = TVGAIN3;
    			ChecksumInput[5] = TVGAIN4;
    			ChecksumInput[6] = TVGAIN5;
    			ChecksumInput[7] = TVGAIN6;
    			checksumLoops = 8;
    		break;
    		case 16 : //THRBW
    		case 25 : //BC_THRBW
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = P1_THR_0;
    			ChecksumInput[2] = P1_THR_1;
    			ChecksumInput[3] = P1_THR_2;
    			ChecksumInput[4] = P1_THR_3;
    			ChecksumInput[5] = P1_THR_4;
    			ChecksumInput[6] = P1_THR_5;
    			ChecksumInput[7] = P1_THR_6;
    			ChecksumInput[8] = P1_THR_7;
    			ChecksumInput[9] = P1_THR_8;
    			ChecksumInput[10] = P1_THR_9;
    			ChecksumInput[11] = P1_THR_10;
    			ChecksumInput[12] = P1_THR_11;
    			ChecksumInput[13] = P1_THR_12;
    			ChecksumInput[14] = P1_THR_13;
    			ChecksumInput[15] = P1_THR_14;
    			ChecksumInput[16] = P1_THR_15;
    			ChecksumInput[17] = P2_THR_0;
    			ChecksumInput[18] = P2_THR_1;
    			ChecksumInput[19] = P2_THR_2;
    			ChecksumInput[20] = P2_THR_3;
    			ChecksumInput[21] = P2_THR_4;
    			ChecksumInput[22] = P2_THR_5;
    			ChecksumInput[23] = P2_THR_6;
    			ChecksumInput[24] = P2_THR_7;
    			ChecksumInput[25] = P2_THR_8;
    			ChecksumInput[26] = P2_THR_9;
    			ChecksumInput[27] = P2_THR_10;
    			ChecksumInput[28] = P2_THR_11;
    			ChecksumInput[29] = P2_THR_12;
    			ChecksumInput[30] = P2_THR_13;
    			ChecksumInput[31] = P2_THR_14;
    			ChecksumInput[32] = P2_THR_15;
    			checksumLoops = 33;
    		break;
    		case 12 : //EEBW
    		case 23 : //BC_EEBW
    			ChecksumInput[0] = cmd;
    			ChecksumInput[1] = USER_DATA1;
    			ChecksumInput[2] = USER_DATA2;
    			ChecksumInput[3] = USER_DATA3;
    			ChecksumInput[4] = USER_DATA4;
    			ChecksumInput[5] = USER_DATA5;
    			ChecksumInput[6] = USER_DATA6;
    			ChecksumInput[7] = USER_DATA7;
    			ChecksumInput[8] = USER_DATA8;
    			ChecksumInput[9] = USER_DATA9;
    			ChecksumInput[10] = USER_DATA10;
    			ChecksumInput[11] = USER_DATA11;
    			ChecksumInput[12] = USER_DATA12;
    			ChecksumInput[13] = USER_DATA13;
    			ChecksumInput[14] = USER_DATA14;
    			ChecksumInput[15] = USER_DATA15;
    			ChecksumInput[16] = USER_DATA16;
    			ChecksumInput[17] = USER_DATA17;
    			ChecksumInput[18] = USER_DATA18;
    			ChecksumInput[19] = USER_DATA19;
    			ChecksumInput[20] = USER_DATA20;
    			ChecksumInput[21] = TVGAIN0;
    			ChecksumInput[22] = TVGAIN1;
    			ChecksumInput[23] = TVGAIN2;
    			ChecksumInput[24] = TVGAIN3;
    			ChecksumInput[25] = TVGAIN4;
    			ChecksumInput[26] = TVGAIN5;
    			ChecksumInput[27] = TVGAIN6;
    			ChecksumInput[28] = INIT_GAIN;
    			ChecksumInput[29] = FREQUENCY;
    			ChecksumInput[30] = DEADTIME;
    			ChecksumInput[31] = PULSE_P1;
    			ChecksumInput[32] = PULSE_P2;
    			ChecksumInput[33] = CURR_LIM_P1;
    			ChecksumInput[34] = CURR_LIM_P2;
    			ChecksumInput[35] = REC_LENGTH;
    			ChecksumInput[36] = FREQ_DIAG;
    			ChecksumInput[37] = SAT_FDIAG_TH;
    			ChecksumInput[38] = FVOLT_DEC;
    			ChecksumInput[39] = DECPL_TEMP;
    			ChecksumInput[40] = DSP_SCALE;
    			ChecksumInput[41] = TEMP_TRIM;
    			ChecksumInput[42] = P1_GAIN_CTRL;
    			ChecksumInput[43] = P2_GAIN_CTRL;
    			checksumLoops = 44;
    		break;
    		default: break;
    	}
    
    	if (ChecksumInput[0]<17) //only re-append command address for non-broadcast commands.
    	{
    		ChecksumInput[0] = ChecksumInput[0] + (uartAddr << 5);
    	}
    	
    	uint16_t carry = 0;
    
    	for (int i = 0; i < checksumLoops; i++)
    	{
    		if ((ChecksumInput[i] + carry) < carry)
    		{
    			carry = carry + ChecksumInput[i] + 1;
    		}
    		else
    		{
    			carry = carry + ChecksumInput[i];
    		}
    
    		if (carry > 0xFF)
    		{
    		  carry = carry - 255;
    		}
    	}
    	
    	carry = (~carry & 0x00FF);
    	return carry;
    }
    
    /*------------------------------------------------- tciIndexRW -----
     |  Function tciIndexRW
     |
     |  Purpose:  Read or write the TCI index command.
     |		TODO: Enable all commands to be written. Update user EEPROM variables based on index read.
     |
     |  Parameters:
     |		index (IN) -- TCI index (0-15) to read or write.
     |		wTrue (IN) -- when true, issue a TCI write command. When false, issue a TCI read command.
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::tciIndexRW(byte index, bool wTrue)
    {
    	#ifdef EnTCI
    	int dataLength = 0;		// number of bits per TCI index
    	String zeroString = "";	// string of zeros to append to the end of the binary string for the checksum calculation
    	String dataString = "";	// entire index data string with appended zeros for checksum calculation
    	byte dataLoops = 0;		// based on the number elements to be passed into the checksum calaculation after appending zeros
    	byte bufTCI[46];		// transmit TCI buffer for all index commands
    	byte data = 0xFF;		// idle-high data transmit data
    	byte zeroPadding = 0;	// byte-number of zeros to append to the end of the binary string for the checksum calculation 
    	byte bitIgnore = 0;		// number of bits to ignore at the end of the concatenated bufTCI index string
    	
    	if (wTrue == true) // TCI write command
    	{
    		bufTCI[0] = 0x1F & (0x10 + index); // set first byte with write bit and index
    		switch(index)
    		{
    			case 0: dataLength = 8; break; //read only
    			case 1: dataLength = 24; break; //read only
    			case 2: zeroPadding = 3; dataLength = 8; zeroString = "000";  bitIgnore = 0; 
    				bufTCI[1] = FREQUENCY;
    				break;
    			case 3: zeroPadding = 1; dataLength = 18; zeroString = "0"; bitIgnore = 0; 
    				//TODO
    				break;
    			case 4: zeroPadding = 3; dataLength = 8; zeroString = "000"; bitIgnore = 0;
    				//TODO
    				break;
    			case 5: zeroPadding = 3; dataLength = 124; zeroString = "000"; bitIgnore = 4; 
    					bufTCI[1] = P1_THR_0;
    					bufTCI[2] = P1_THR_1;
    					bufTCI[3] = P1_THR_2;
    					bufTCI[4] = P1_THR_3;
    					bufTCI[5] = P1_THR_4;
    					bufTCI[6] = P1_THR_5;
    					bufTCI[7] = P1_THR_6;
    					bufTCI[8] = P1_THR_7;
    					bufTCI[9] = P1_THR_8;
    					bufTCI[10] = P1_THR_9;
    					bufTCI[11] = P1_THR_10;
    					bufTCI[12] = P1_THR_11;
    					bufTCI[13] = P1_THR_12;
    					bufTCI[14] = P1_THR_13;
    					bufTCI[15] = P1_THR_14;
    					bufTCI[16] = (P1_THR_15 & 0x0F) << 4; //TH_P1_OFF only
    				break;
    			case 6: zeroPadding = 3; dataLength = 124; zeroString = "000"; bitIgnore = 4;
    					bufTCI[1] = P2_THR_0;
    					bufTCI[2] = P2_THR_1;
    					bufTCI[3] = P2_THR_2;
    					bufTCI[4] = P2_THR_3;
    					bufTCI[5] = P2_THR_4;
    					bufTCI[6] = P2_THR_5;
    					bufTCI[7] = P2_THR_6;
    					bufTCI[8] = P2_THR_7;
    					bufTCI[9] = P2_THR_8;
    					bufTCI[10] = P2_THR_9;
    					bufTCI[11] = P2_THR_10;
    					bufTCI[12] = P2_THR_11;
    					bufTCI[13] = P2_THR_12;
    					bufTCI[14] = P2_THR_13;
    					bufTCI[15] = P2_THR_14;
    					bufTCI[16] = (P2_THR_15 & 0x0F) << 4; //TH_P2_OFF only
    				break;
    			case 7: zeroPadding = 1; dataLength = 42; zeroString = "0"; bitIgnore = 0; 
    				//TODO
    				break;
    			case 8: zeroPadding = 3; dataLength = 56; zeroString = "000"; bitIgnore = 0; 
    					bufTCI[1] = TVGAIN0;
    					bufTCI[2] = TVGAIN1;
    					bufTCI[3] = TVGAIN2;
    					bufTCI[4] = TVGAIN3;
    					bufTCI[5] = TVGAIN4;
    					bufTCI[6] = TVGAIN5;
    					bufTCI[7] = TVGAIN6;
    				break;
    			case 9: zeroPadding = 3; dataLength = 160; zeroString = "000"; bitIgnore = 0; 
    				//TODO
    				break;
    			case 10: zeroPadding = 5; dataLength = 46; zeroString = "00000"; bitIgnore = 0; 
    				//TODO
    				break;
    			case 11: zeroPadding = 3; dataLength = 8; zeroString = "000"; bitIgnore = 0; 
    				bufTCI[1] = EE_CNTRL;
    				break;
    			case 12: dataLength = 1024; break; //read only
    			case 13: zeroPadding = 3; zeroString = "000";  dataLength = 352; bitIgnore = 0;			
    					bufTCI[1] = USER_DATA1;
    					bufTCI[2] = USER_DATA2;
    					bufTCI[3] = USER_DATA3;
    					bufTCI[4] = USER_DATA4;
    					bufTCI[5] = USER_DATA5;
    					bufTCI[6] = USER_DATA6;
    					bufTCI[7] = USER_DATA7;
    					bufTCI[8] = USER_DATA8;
    					bufTCI[9] = USER_DATA9;
    					bufTCI[10] = USER_DATA10;
    					bufTCI[11] = USER_DATA11;
    					bufTCI[12] = USER_DATA12;
    					bufTCI[13] = USER_DATA13;
    					bufTCI[14] = USER_DATA14;
    					bufTCI[15] = USER_DATA15;
    					bufTCI[16] = USER_DATA16;
    					bufTCI[17] = USER_DATA17;
    					bufTCI[18] = USER_DATA18;
    					bufTCI[19] = USER_DATA19;
    					bufTCI[20] = USER_DATA20;
    					bufTCI[21] = TVGAIN0;
    					bufTCI[22] = TVGAIN1;
    					bufTCI[23] = TVGAIN2;
    					bufTCI[24] = TVGAIN3;
    					bufTCI[25] = TVGAIN4;
    					bufTCI[26] = TVGAIN5;
    					bufTCI[27] = TVGAIN6;
    					bufTCI[28] = INIT_GAIN;
    					bufTCI[29] = FREQUENCY;
    					bufTCI[30] = DEADTIME;
    					bufTCI[31] = PULSE_P1;
    					bufTCI[32] = PULSE_P2;
    					bufTCI[33] = CURR_LIM_P1;
    					bufTCI[34] = CURR_LIM_P2;
    					bufTCI[35] = REC_LENGTH;
    					bufTCI[36] = FREQ_DIAG;
    					bufTCI[37] = SAT_FDIAG_TH;
    					bufTCI[38] = FVOLT_DEC;
    					bufTCI[39] = DECPL_TEMP;
    					bufTCI[40] = DSP_SCALE;
    					bufTCI[41] = TEMP_TRIM;
    					bufTCI[42] = P1_GAIN_CTRL;
    					bufTCI[43] = P2_GAIN_CTRL;
    					bufTCI[44] = EE_CRC;
    				break;
    			case 14: break; //read only (reserved)
    			case 15: dataLength = 16; break; //read only						
    			default: return;
    		}
    		
    		// calculate checksum	
    			// convert byte to binary string	
    				dataLoops = ((dataLength+((zeroPadding+bitIgnore)-3))/8) + 1;		
    				
    				String tempString = "";
    				for (int i=0; i<dataLoops; i++)
    				{
    					tempString = String((int)bufTCI[i],BIN);
    					while (tempString.length() < 8)
    					{
    						tempString = "0" + tempString;	// add leading zero to get 8 bit BIN representaiton
    					}
    					dataString.concat(tempString);
    				}							
    				dataString = dataString.substring(3); // truncate leading zeros
    				dataString.concat(zeroString); // append zero padding to binary string
    				
    			// convert binary string to bytes for checksum calculation
    				String parsed = "";
    				byte value = 0;
    				for(int k=0; k < dataLoops; k++)
    				{
    					parsed = dataString.substring(k*8,(k*8)+8);
    					char s[9];
    					parsed.toCharArray(s,9);
    					for (int i=0; i< strlen(s); i++)  // for every character in the string  strlen(s) returns the length of a char array
    					{
    					  value *= 2; // double the result so far
    					  if (s[i] == '1') value++;  //add 1 if needed
    					}
    					bufTCI[k] = value;
    				}
    			
    			// generate TCI checksum
    			uint16_t carry = 0;	
    				for (int i = 0; i < dataLoops; i++)
    				{
    					if ((bufTCI[i] + carry) < carry)
    					{
    						carry = carry + bufTCI[i] + 1;
    					}
    					else
    					{
    						carry = carry + bufTCI[i];
    					}
    
    					if (carry > 0xFF)
    					{
    					  carry = carry - 255;
    					}
    				}
    				carry = (~carry & 0x00FF);
    
    		// send CFG_TCI low pulse of 1.27ms
    		tciCommand(4);
       
    		// transmit r/w , index, and data bits. 
    			for (int m = 0; m < dataLoops-1; m++)
    			{
    				data = bufTCI[m];
    				pga460::tciByteToggle(data,0); // send bits 7..0			
    			} 
    			
    	   // send last byte without zero padding
    			data = bufTCI[dataLoops-1];
    			{
    				data = data >> (zeroPadding+bitIgnore);
    				pga460::tciByteToggle(data,(zeroPadding+bitIgnore));			
    			}		 
    			
    	   // send checksum
    		   data = (byte)carry;
    		   pga460::tciByteToggle(data,0);
    	}
    	
    	else // TCI read command
    	{
    		int recvLength = 0; 	// number of bits to expect for the index to be read
    		bool recvState = 0xFF;	// receive state initiated to idle high
    		bool lastState = 0xFF;	// last state read initiated to idle high
    		int element = 0;		// bufRecv byte element to save bit capture to
    		int bitCount = 0;		// number of bits read to auto increment bufRecv element after 8 hits
    		
    		switch (index)
    		{
    			case 0: recvLength = 8; break;
    			case 1: recvLength = 24; break;
    			case 2: recvLength = 8; break;
    			case 3: recvLength = 18; break;
    			case 4: recvLength = 8; break;
    			case 5: recvLength = 124; break;
    			case 6: recvLength = 124; break;
    			case 7: recvLength = 42; break;
    			case 8: recvLength = 56; break;
    			case 9: recvLength = 160; break;
    			case 10: recvLength = 46; break;
    			case 11: recvLength = 8; break;
    			case 12: recvLength = 1024; break;
    			case 13: recvLength = 352; break;
    			case 14: recvLength = 0; break;
    			case 15: recvLength = 16; break;
    			default: return;
    		}		
    				
    		memset(bufRecv, 0xFF, sizeof(bufRecv)); // idle-high receive buffer data
    		starttime = millis();
    		
    		// send CFG_TCI low pulse of 1.27ms
    		tciCommand(4); 
    		data = 0x1F & (0x00 + index);
    		pga460::tciByteToggle(data,3);
    		delayMicroseconds(100); //TCI deadtime	 
     		
    		// capture first response toggle by sampling center of 300us TCI bit indicate 0 or 1
    		delayMicroseconds(150);
    		lastState=digitalRead(TCI_RX);
    		bitWrite(bufRecv[element], 7-bitCount, digitalRead(TCI_RX));  
    		bitCount++;
    		
    		while((millis() - starttime) < 500) // timeout after 0.5 seconds
    		{
    			recvState = digitalRead(TCI_RX);
    			if (((recvState != lastState) && (recvState == 0))) // check for high-to-low toggle
    			{
    				// sample center of 300us TCI bit indicate 0 or 1
    				delayMicroseconds(150);
    				bitWrite(bufRecv[element], 7-bitCount, digitalRead(TCI_RX));				
    				bitCount++;
    				if (bitCount == 8)
    				{
    					bitCount = 0;
    					element++;
    				}
    			}
    			lastState = recvState;
    			delayMicroseconds(10); // master defined deglitcher timeout
    		}
    	}
    	return;
    	#endif
    }
    
    /*------------------------------------------------- tciByteToggle -----
     |  Function tciByteToggle
     |
     |  Purpose:  Toggle the TCI_TX pin based on the bit data of the byte data passed in. 
     |		A bit value of '1' toggles TCI_TX low for 100us, then holds it high for 200us.
     |		A bit value of '0' toggles TCI_TX low for 200us, then holds it high for 100us.
     |
     |  Parameters:
     |		data (IN) -- byte value to bit parse.
     |		zeroPadding (IN) -- bit toggle based on the number of zeros padded. Zero padding is for checksum calculation only.
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::tciByteToggle(byte data, byte zeroPadding)
    {
    	#ifdef EnTCI
    	byte mask = 0x80;
    	int numBits = 8;
    	switch (zeroPadding)
    	{
    		case 0: mask = 0x80; numBits = 8; break;
    		case 1: mask = 0x40; numBits = 7; break;
    		case 2: mask = 0x20; numBits = 6; break;
    		case 3: mask = 0x10; numBits = 5; break;
    		case 4: mask = 0x08; numBits = 4; break;
    		case 5: mask = 0x04; numBits = 3; break;
    		case 6: mask = 0x02; numBits = 2; break;
    		case 7: mask = 0x01; numBits = 1; break;
    		default: return;
    	}
    	
    	for (int n = 0; n < numBits; n++)
    	   {				   
    		   // set line low for 100us if bit is 1, low for 200us if bit is 0
    		   if (data & mask) // consider leftmost bit (MSB out first)
    		   {
    			digitalWrite(TCI_TX, LOW);
    			delayMicroseconds(100);
    			digitalWrite(TCI_TX, HIGH);
    			delayMicroseconds(200);
    		   }
    		   else
    		   {
    			digitalWrite(TCI_TX, LOW);
    			delayMicroseconds(200);
    			digitalWrite(TCI_TX, HIGH);
    			delayMicroseconds(100);				
    		   }							   
    		   data <<= 1; // shift byte left so next bit will be leftmost
    	   }	   
    	   return;
    	   #endif
    }
    
    /*------------------------------------------------- tciRecord -----
     |  Function tciRecord
     |
     |  Purpose:  Record TCI_RX toggle burst and/or low activity to time stamp high-to-low transitions representing
    		time-of-flight measurements. The time-of-flight is captures in microseconds, and saved to the ultrasonic
    		measurement results array to later convert time-of-flight to distance in meters.
     |
     |  Parameters:
     |		data (IN) -- byte value to bit parse.
     |		numObj (IN) -- number of objects/toggles to monitor the TCI_RX line for (limited to 8 for this library)
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::tciRecord(byte numObj)
    {
    	#ifdef EnTCI
    	bool recvState = 0;
    	bool lastState = 0;
    	tciToggle = micros();
    	byte objCount = 0;
    	starttime = millis();
    	delayMicroseconds(300); //wait until after STAT bits are toggled by PGA460
    	
    	while(((millis() - starttime) < 100) && (objCount < numObj)) // timeout after 100ms, or after set number of objects are registered
    	{
    		recvState = digitalRead(TCI_RX);
    		if (((recvState != lastState) && (recvState == 0))) // check for high-to-low toggle of TCI_RX line
    		{
    			objTime[objCount] = (int)(micros() - tciToggle); // capture time-of-flight
    			objCount++;
    		}
    		lastState = recvState;
    		delayMicroseconds(10); // master implemented deglitcher //8cm resolution due to micros timer
    	}
    	
    	if (objCount == (numObj-1)) // if number of objects fills before timer expires
    	{
    		delay(100-(millis() - starttime)); //wait a total time of 100ms regardless
    	}	
    
    	// save each TCI time-of-flight to ultrasonic measurement results array (16 bit parsed into two 8 byte elements)
    	for (int i = 0; i < objCount; i++)
    	{	
    		ultraMeasResult[(i*4)+1] = (objTime[i] >> 8) & 0x00FF; // MSB
    		ultraMeasResult[(i*4)+2] = 0x00FF; //LSB
    	}
    	#endif
    }
    
    /*------------------------------------------------- tciCommand -----
     |  Function tciCommand
     |
     |  Purpose:  Toggle TCI_TX low for micro second duration based on nominal requirement of TCI command.
     |
     |  Parameters:
     |		cmd (IN) -- which TCI command to issue
     |			• 0 = BURST/LISTEN (Preset1)
     |			• 1 = BURST/LISTEN (Preset2)
     |			• 2 = LISTEN only (Preset1)
     |			• 3 = LISTEN only (Preset2)
     |			• 4 = Device configuration
     |			• 5 = Temperature measurement
     |			• 6 = Noise level
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::tciCommand(byte cmd)
    {
    	#ifdef EnTCI
    	digitalWrite(TCI_TX, LOW);
    	
    	switch (cmd)
    	{	
    		case 0: delayMicroseconds(400); break; //send P1BL_TCI low pulse
    		case 1: delayMicroseconds(1010); break; //send P2BL_TCI low pulse
    		case 2: delayMicroseconds(780); break; //send P1LO_TCI low pulse
    		case 3: delayMicroseconds(580); break; //send P2LO_TCI low pulse
    		case 4: delayMicroseconds(1270); break; //send CFG_TCI low pulse
    		case 5: delayMicroseconds(1550); break; //send TEMP_TCI low pulse
    		case 6: delayMicroseconds(2200); break; //send NOISE_TCI low pulse
    		default: break;	 
    	}
    
    	digitalWrite(TCI_TX, HIGH);
    	delayMicroseconds(100); //TCI deadtime
    	#endif
    }
    
    /*------------------------------------------------- spiTransfer -----
     |  Function spiTransfer
     |
     |  Purpose:  Transfers one byte over the SPI bus, both sending and receiving. 
     |			Captures MISO data in global byte-array.
     |
     |  Parameters:
     |		mosi (IN) -- MOSI data byte array to transmit over SPI
     |		size (IN) -- size of MOSI data byte array
     |
     |  Returns: byte representation of calculated checksum value
     *-------------------------------------------------------------------*/
    void pga460::spiTransfer(byte* mosi, byte size )
    {
    	#ifdef EnSPI	
    	memset(misoBuf, 0x00, sizeof(misoBuf)); // idle-low receive buffer data
    	
    	for (int i = 0; i<size; i++)
    	{
    		digitalWrite(SPI_CS, LOW);
    		misoBuf[i] = usscSPI.transfer(mosi[i]);
    		digitalWrite(SPI_CS, HIGH);
    	}
    	return;
    	#endif
    }
    
    /*------------------------------------------------- spiMosiIdle-----
     |  Function spiMosiIdle
     |
     |  Purpose:  Forces MOSI of 0xFF to idle high master output, while
     |			MISO pin returns valid data.
     |
     |  Parameters:
     |		size (IN) -- number of MISO data bytes expected from slave
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::spiMosiIdle(byte size){		
    	#ifdef EnSPI	
    	//memset(misoBuf, 0x00, sizeof(misoBuf)); // idle-low receive buffer data
    	
    	digitalWrite(SPI_CS, LOW);
    	for (int i = 0; i<size; i++)
    	{
    		digitalWrite(SPI_CS, LOW);
    		misoBuf[i] = usscSPI.transfer(0xFE);
    		digitalWrite(SPI_CS, HIGH);
    	}
    	digitalWrite(SPI_CS, HIGH);
    	return;
    	#endif
    }
    
    
    /*------------------------------------------------- pga460SerialFlush -----
     |  Function pga460SerialFlush
     |
     |  Purpose:  Clears the MSP430's UART receiver buffer
     |
     |  Parameters:
     |		none
     |
     |  Returns: none
     *-------------------------------------------------------------------*/
    void pga460::pga460SerialFlush(){
    	delay(10);
    	Serial1.flush();
    	while((Serial1.available() > 0))// || (Serial1.read() < 0xFF)) 
    	{
    		char temp = Serial1.read();
    		//Serial1.flush();
    	}
    	
    	//redundant clear
    	for (int i = 0; i < 10; i++)
    	 {
    	   while (Serial.available() > 0)
    	   {
    		 char k = Serial.read();
    		 delay(1);
    	   }
    	   delay(1);
    	 }
    	 
    	Serial1.flush();
    	return;
    }
    
    /*------------------------------------------------- toggleLEDs -----
     |  Function toggleLEDs
     |
     |  Purpose:  Set the BOOSTXL-PGA460 diagnostic LED state to ON or OFF.
     |
     |  Parameters:
     |		ds1State (IN) -- state of BOOSTXL-PGA460 RED LED populated at D9
     |		fdiagState (IN) -- state of BOOSTXL-PGA460 RED LED populated at D8
     |		vdiagate (IN) -- state of BOOSTXL-PGA460 RED LED populated at D7
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::toggleLEDs(bool ds1State, bool fdiagState, bool vdiagState){
    	digitalWrite(DS1_LED, ds1State); digitalWrite(F_DIAG_LED, fdiagState); digitalWrite(V_DIAG_LED, vdiagState);
    	return;
    }
    
    /*------------------------------------------------- triangulation -----
     |  Function triangulation
     |
     |  Purpose:  Uses the law of cosines to compute the position of the
     |			targeted object from transceiver S1.
     |
     |  Parameters:
     |		distanceA (IN) -- distance (m) from sensor module 1 (S1) to the targeted object based on UMR result
     |		distanceB (IN) -- distance (m) between sensor module 1 (S1) and sensor module 2 (S2)
     |		distanceC (IN) -- distance (m) from sensor module 2 (S2) to the targeted object based on UMR result
     |
     |  Returns:  angle (degrees) from transceiver element S1 to the targeted object
     *-------------------------------------------------------------------*/
    double pga460::triangulation(double a, double b, double c){
    	#ifdef EnTri
    	// LAW OF COSINES
    	double inAngle;
    	if (a+b>c)
    	{
    		return inAngle =(acos(((a*a)+(b*b)-(c*c))/(2*a*b))) * 57.3; //Radian to Degree = Rad * (180/PI)
    	}
    	else
    	{
    		return 360;
    	}
    	
    	// COORDINATE
    	// TODO
    	#endif
    }
    
    /*------------------------------------------------- registerRead -----
     |  Function registerRead
     |
     |  Purpose:  Read single register data from PGA460
     |
     |  Parameters:
     |		addr (IN) -- PGA460 register address to read data from
     |
     |  Returns:  8-bit data read from register
     *-------------------------------------------------------------------*/
    byte pga460::registerRead(byte addr){
    	byte data = 0x00;
    	byte temp = 0;
    	
    	if (comm == 2)
    	{
    		owuShift = 1; // OWU receive buffer offset to ignore transmitted data
    	}
    	else
    	{
    		owuShift = 0;
    	}	
    	
    	pga460SerialFlush();
    	
    	regAddr = addr;
    	byte buf9[4] = {syncByte, SRR, regAddr, calcChecksum(SRR)};
    	if (comm == 0 || comm == 2) // UART or OWU mode
    	{
    		Serial1.write(buf9, sizeof(buf9));
    	}
    	if (comm == 3) // SPI mode
    	{
    		spiTransfer(buf9, sizeof(buf9));
    	}
    	delay(10);
    	if (comm == 0 || comm == 2) // UART or OWU mode
    	{
    		for(int n=0; n<3; n++)
    		{
    		   if(n==1-owuShift)
    		   {
    				data = Serial1.read(); // store read data
    		   }
    		   else
    		   {
    			   temp = Serial1.read();
    		   }
    		}
    	}
    	if (comm == 3) // SPI mode
    	{
    		spiMosiIdle(3);
    		data = misoBuf[1];
    	}	
    	
    	return data;
    }
    	
    /*------------------------------------------------- registerWrite -----
     |  Function registerWrite
     |
     |  Purpose:  Write single register data to PGA460
     |
     |  Parameters:
     |		addr (IN) -- PGA460 register address to write data to
     |		data (IN) -- 8-bit data value to write into register
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
     byte pga460::registerWrite(byte addr, byte data){
    	regAddr = addr;
    	regData = data;	
    	byte buf10[5] = {syncByte, SRW, regAddr, regData, calcChecksum(SRW)};
    	if (comm == 0 || comm == 2) // UART or OWU mode
    	{
    		Serial1.write(buf10, sizeof(buf10));
    	}
    	if (comm == 3) // SPI mode
    	{
    		spiTransfer(buf10, sizeof(buf10));
    	}
    	delay(10);
    }
    
    /*------------------------------------------------- autoThreshold -----
     |  Function autoThreshold
     |
     |  Purpose:  Automatically assigns threshold time and level values
     |  			based on a no-object burst/listen command
     |
     |  Parameters:
     |		cmd (IN) -- preset 1 or 2 burst and/or listen command to run
     |		noiseMargin (IN) -- margin between maximum downsampled noise
     |						value and the threshold level in intervals
     |						of 8.
     |		windowIndex (IN) -- spacing between each threshold time as an
     |						index (refer to datasheet for microsecond
     |						equivalent). To use the existing threshold
     |						times, enter a value of '16'.
     |		autoMax (IN) -- automatically set threshold levels up to this
     |					threshold point (maximum is 12). Remaining levels
     |					will not change.
     |		loops (IN) -- number of command loops to run to collect a
     |					running average of the echo data dump points.
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::autoThreshold(byte cmd, byte noiseMargin, byte windowIndex, byte autoMax, byte avgLoops)
    {
    	#ifdef EnAutoThr
    	// local variables
    	byte thrTime[6]; // threshold time values for selected preset
    	byte thrLevel[10]; //threshold level values for selected preset
    	byte thrMax[12]; // maximum echo data dump values per partition
    	byte presetOffset = 0; // determines if regsiter threshold address space is initialized at P1 or P2
    	byte thrOffset = 0; // -6 to +7 where MSB is sign value
    	bool thrOffsetFlag = 0; //when high, the level offset value is updated
    	
    	//read existing threhsold values into thrTime array
    	switch (cmd)
    	{
    		//Preset 1 command
    		case 0:
    		case 2:
    			pga460::thresholdBulkRead(1);			
    			break;		
    		//Preset 2 command
    		case 1:
    		case 3:
    			pga460::thresholdBulkRead(2);
    			presetOffset = 16;
    			break;		
    		//Invalid command
    		default:
    			return;
    			break;
    	}
    	
    	// set thrTime and thrLevel to existing threshold time and level values respectively
    	for (byte h = 0; h<6; h++)
    	{
    		thrTime[h] = bulkThr[h + presetOffset];
    	}
    	for (byte g = 0; g<10; g++)
    	{
    		thrLevel[g] = bulkThr[g + 6 + presetOffset];
    	}
    	
    	// replace each preset time with windowIndex for the number of points to auto-calc
    	if (windowIndex >= 16)
    	{
    		//skip threshold-time configuration
    	}
    	else
    	{
    		for (byte i = 0; i < 12; i+=2)
    		{	
    	
    			if (autoMax > i)
    			{
    				thrTime[i/2] = thrTime[i/2] & 0x0F;
    				thrTime[i/2] = (windowIndex << 4) | thrTime[i/2];
    				if (autoMax > i+1)
    				{
    					thrTime[i/2] = thrTime[i/2] & 0xF0;
    					thrTime[i/2] = (windowIndex & 0x0F) | thrTime[i/2];
    				}
    			}
    		}
    	}
    
    	// run burst-and-listen to collect EDD data
    	pga460::runEchoDataDump(cmd);
    	
    	// read the record length value for the preset
    	byte recLength = pga460::registerRead(0x22); // read REC_LENGTH Register
    	switch(cmd)
    	{
    		//Preset 1 command
    		case 0:
    		case 2:
    			recLength = (recLength >> 4) & 0x0F;			
    			break;		
    		//Preset 2 command
    		case 1:
    		case 3:
    			recLength = recLength & 0x0F;
    			break;		
    		//Invalid command
    		default:
    			return;
    			break;
    	}
    	
    	// convert record length value to time equivalent in microseconds
    	unsigned int recTime = (recLength + 1) * 4096;
    	
    	//determine the number of threshold points that are within the record length time
    	byte numPoints = 0;
    	byte thrTimeReg = 0;
    	unsigned int thrMicro = 0; // threhsold total time in microseconds
    	unsigned int eddMarker[12]; // echo data dump time marker between each threhsold point
    	for (thrTimeReg = 0; thrTimeReg < 6; thrTimeReg++)
    	{		
    		// check threshold 1 of 2 in single register
    		switch ((thrTime[thrTimeReg] >> 4) & 0x0F)
    		{			
    			case 0: thrMicro += 100; break;
    			case 1: thrMicro += 200; break;
    			case 2: thrMicro += 300; break;
    			case 3: thrMicro += 400; break;
    			case 4: thrMicro += 600; break;
    			case 5: thrMicro += 800; break;
    			case 6: thrMicro += 1000; break;
    			case 7: thrMicro += 1200; break;
    			case 8: thrMicro += 1400; break;
    			case 9: thrMicro += 2000; break;
    			case 10: thrMicro += 2400; break;
    			case 11: thrMicro += 3200; break;
    			case 12: thrMicro += 4000; break;
    			case 13: thrMicro += 5200; break;
    			case 14: thrMicro += 6400; break;
    			case 15: thrMicro += 8000; break;
    			default: break;
    		}
    		eddMarker[thrTimeReg*2] = thrMicro;
    		if (thrMicro >= recTime)
    		{			
    			numPoints = thrTimeReg * 2;
    			thrTimeReg = 6; //exit
    		}
    		else
    		{
    			// check threshold 2 of 2 in single register
    			switch (thrTime[thrTimeReg] & 0x0F)
    			{
    				case 0: thrMicro += 100; break;
    				case 1: thrMicro += 200; break;
    				case 2: thrMicro += 300; break;
    				case 3: thrMicro += 400; break;
    				case 4: thrMicro += 600; break;
    				case 5: thrMicro += 800; break;
    				case 6: thrMicro += 1000; break;
    				case 7: thrMicro += 1200; break;
    				case 8: thrMicro += 1400; break;
    				case 9: thrMicro += 2000; break;
    				case 10: thrMicro += 2400; break;
    				case 11: thrMicro += 3200; break;
    				case 12: thrMicro += 4000; break;
    				case 13: thrMicro += 5200; break;
    				case 14: thrMicro += 6400; break;
    				case 15: thrMicro += 8000; break;
    				default: break;
    			}
    			eddMarker[thrTimeReg*2+1] = thrMicro;
    			if (thrMicro >= recTime)
    			{
    				numPoints = (thrTimeReg * 2) + 1;
    				thrTimeReg = 6; //exit
    			}
    		}	
    	}
    	if (numPoints == 0) //if all points fall within the record length
    	{
    		numPoints = 11;
    	}
    	
    	//convert up to 12 echo data dump markers from microseconds to index
    	byte eddIndex[13];
    	eddIndex[0] = 0;
    	for (byte l = 0; l < 12; l++)
    	{
    		eddIndex[l+1] = ((eddMarker[l]/100)*128)/(recTime/100); // divide by 100 for best accuracy in MSP430
    	}	
    	
    	// downsample the echo data dump based on the number of partitions
    	memset(thrMax, 0x00, 12); // zero thrMax array
    	byte eddLevel = 0;
    	for (byte j = 0; j < numPoints+1; j++)
    	{	
    		eddLevel = 0;
    		for (byte k = eddIndex[j]; k < eddIndex[j+1]; k++)
    		{
    			eddLevel = pga460::pullEchoDataDump(k);
    			if (thrMax[j] < eddLevel)
    			{
    				thrMax[j] = eddLevel;
    			}		
    		}	
    	}
    	//set threhsold points which exceed the record length to same value as last valid value
    	if (numPoints < autoMax)
    	{
    		for (int o = numPoints; o < autoMax; o++)
    		{
    			if (numPoints ==0)
    			{
    				thrMax[o] = 128;
    			}
    			else
    			{
    				thrMax[o] = thrMax[numPoints-1];
    			}
    		}
    	}
    
    	// filter y-max for level compatibility of first eight points
    	for (int m = 0; m < 8; m++)
    	{
    		//first eight levels must be mutliples of eight
    		while ((thrMax[m] % 8 != 0) && (thrMax[m] < 248)) 
    		{
    			thrMax[m] += 1;
    		}
    	}
    	
    	// apply noise floor offset
    	for (int n = 0; n < 12; n++)
    	{
    		if (thrMax[n] + noiseMargin >= 248 && thrMax[n] + noiseMargin < 255)
    		{
    			thrMax[n] = 248;
    			thrOffset = 0b0110; //+6
    			thrOffsetFlag = true;
    		}
    		else if (thrMax[n] + noiseMargin >= 255)
    		{
    			thrMax[n] = 248;
    			thrOffset = 0b0111; // +7
    			thrOffsetFlag = true;
    		}
    		else
    		{
    			thrMax[n] += noiseMargin;
    		}
    	}
    	
    	//convert first eight auto calibrated levels to five-bit equivalents
    	byte rounding = 0;
    	if (autoMax >= 8)
    	{
    		rounding = 8;
    	}
    	else
    	{
    		rounding = autoMax;
    	}
    	for(byte p = 0; p < rounding; p++)
    	{
    		thrMax[p] = thrMax[p] / 8;
    	}
    	
    	// concatenate and merge threshold level register values
    	if (autoMax > 0) //Px_THR_6 L1,L2
    	{
    		thrLevel[0] = (thrLevel[0] & ~0xF8) | (thrMax[0] << 3);
    	}
    	if (autoMax > 1) //Px_THR_6 L1,L2
    	{
    		thrLevel[0] = (thrLevel[0] & ~0x07) | (thrMax[1] >> 2);
    	}
    	
    	if (autoMax > 1) //Px_THR_7 L2,L3,L4
    	{
    		thrLevel[1] = (thrLevel[1] & ~0xC0) | (thrMax[1] << 6);
    	}
    	if (autoMax > 2) //Px_THR_7 L2,L3,L4
    	{
    		thrLevel[1] = (thrLevel[1] & ~0x3E) | (thrMax[2] << 1);
    	}
    	if (autoMax > 3) //Px_THR_7 L2,L3,L4
    	{
    		thrLevel[1] = (thrLevel[1] & ~0x01) | (thrMax[3] >> 4 );
    	}
    	
    	if (autoMax > 3) //Px_THR_8 L4,L5
    	{
    		thrLevel[2] = (thrLevel[2] & ~0xF0) | (thrMax[3] << 4 );
    	}
    	if (autoMax > 4) //Px_THR_8 L4,L5
    	{
    		thrLevel[2] = (thrLevel[2] & ~0x0F) | (thrMax[4] >> 1 );
    	}
    	
    	if (autoMax > 4) //Px_THR_9 L5,L6,L7
    	{
    		thrLevel[3] = (thrLevel[3] & ~0x80) | (thrMax[4] << 7 );
    	}
    	if (autoMax > 5) //Px_THR_9 L5,L6,L7
    	{
    		thrLevel[3] = (thrLevel[3] & ~0x7C) | (thrMax[5] << 2 );
    	}
    	if (autoMax > 6) //Px_THR_9 L5,L6,L7
    	{
    		thrLevel[3] = (thrLevel[3] & ~0x03) | (thrMax[6] >> 3 );
    	}
    	
    	if (autoMax > 6) //Px_THR_10 L7,L8
    	{
    		thrLevel[4] = (thrLevel[4] & ~0xE0) | (thrMax[6] << 5 );
    	}
    	if (autoMax > 7) //Px_THR_10 L7,L8
    	{
    		thrLevel[4] = (thrLevel[4] & ~0x1F) | (thrMax[7]);
    	}
    	
    	if (autoMax > 8) //Px_THR_11 L9 
    	{
    		thrLevel[5] = thrMax[8];
    	}
    	if (autoMax > 9) //Px_THR_12 L10
    	{
    		thrLevel[6] = thrMax[9];
    	}
    	if (autoMax > 10) //Px_THR_13 L11 
    	{
    		thrLevel[7] = thrMax[10];
    	}
    	if (autoMax > 11) //Px_THR_14 L12
    	{
    		thrLevel[8] = thrMax[11];
    	}
    	if (thrOffsetFlag == true) //Px_THR_15 LOff
    	{
    		thrLevel[9] = thrOffset & 0x0F;
    	}
    	
    	// update threshold register values
    	switch(cmd)
    	{
    		//Preset 1 command
    		case 0:
    		case 2:				
    			P1_THR_0 = thrTime[0];
    			P1_THR_1 = thrTime[1];
    			P1_THR_2 = thrTime[2];
    			P1_THR_3 = thrTime[3];
    			P1_THR_4 = thrTime[4];
    			P1_THR_5 = thrTime[5];
    			P1_THR_6 = thrLevel[0];
    			P1_THR_7 = thrLevel[1];
    			P1_THR_8 = thrLevel[2];
    			P1_THR_9 = thrLevel[3];
    			P1_THR_10 = thrLevel[4];
    			P1_THR_11 = thrLevel[5];
    			P1_THR_12 = thrLevel[6];
    			P1_THR_13 = thrLevel[7];
    			P1_THR_14 = thrLevel[8];
    			P1_THR_15 = thrLevel[9];
    			
    			pga460::thresholdBulkRead(2);
    			presetOffset = 16;
    			
    			P2_THR_0 = bulkThr[0 + presetOffset];
    			P2_THR_1 = bulkThr[1 + presetOffset];
    			P2_THR_2 = bulkThr[2 + presetOffset];
    			P2_THR_3 = bulkThr[3 + presetOffset];
    			P2_THR_4 = bulkThr[4 + presetOffset];
    			P2_THR_5 = bulkThr[5 + presetOffset];
    			P2_THR_6 = bulkThr[6 + presetOffset];
    			P2_THR_7 = bulkThr[7 + presetOffset];
    			P2_THR_8 = bulkThr[8 + presetOffset];
    			P2_THR_9 = bulkThr[9 + presetOffset];
    			P2_THR_10 = bulkThr[10 + presetOffset];
    			P2_THR_11 = bulkThr[11 + presetOffset];
    			P2_THR_12 = bulkThr[12 + presetOffset];
    			P2_THR_13 = bulkThr[13 + presetOffset];
    			P2_THR_14 = bulkThr[14 + presetOffset];
    			P2_THR_15 = bulkThr[15 + presetOffset];		
    			break;		
    		//Preset 2 command
    		case 1:
    		case 3:
    			P2_THR_0 = thrTime[0];
    			P2_THR_1 = thrTime[1];
    			P2_THR_2 = thrTime[2];
    			P2_THR_3 = thrTime[3];
    			P2_THR_4 = thrTime[4];
    			P2_THR_5 = thrTime[5];
    			P2_THR_6 = thrLevel[0];
    			P2_THR_7 = thrLevel[1];
    			P2_THR_8 = thrLevel[2];
    			P2_THR_9 = thrLevel[3];
    			P2_THR_10 = thrLevel[4];
    			P2_THR_11 = thrLevel[5];
    			P2_THR_12 = thrLevel[6];
    			P2_THR_13 = thrLevel[7];
    			P2_THR_14 = thrLevel[8];
    			P2_THR_15 = thrLevel[9];
    			
    			pga460::thresholdBulkRead(1);
    			presetOffset = 0;
    			
    			P1_THR_0 = bulkThr[0 + presetOffset];
    			P1_THR_1 = bulkThr[1 + presetOffset];
    			P1_THR_2 = bulkThr[2 + presetOffset];
    			P1_THR_3 = bulkThr[3 + presetOffset];
    			P1_THR_4 = bulkThr[4 + presetOffset];
    			P1_THR_5 = bulkThr[5 + presetOffset];
    			P1_THR_6 = bulkThr[6 + presetOffset];
    			P1_THR_7 = bulkThr[7 + presetOffset];
    			P1_THR_8 = bulkThr[8 + presetOffset];
    			P1_THR_9 = bulkThr[9 + presetOffset];
    			P1_THR_10 = bulkThr[10 + presetOffset];
    			P1_THR_11 = bulkThr[11 + presetOffset];
    			P1_THR_12 = bulkThr[12 + presetOffset];
    			P1_THR_13 = bulkThr[13 + presetOffset];
    			P1_THR_14 = bulkThr[14 + presetOffset];
    			P1_THR_15 = bulkThr[15 + presetOffset];	
    			break;		
    		//Invalid command
    		default:
    			return;
    			break;
    	}
    	
    	byte p1ThrMap[16] = {P1_THR_0, P1_THR_1, P1_THR_2, P1_THR_3, P1_THR_4, P1_THR_5,
    							P1_THR_6, P1_THR_7, P1_THR_8, P1_THR_9, P1_THR_10, P1_THR_11,
    							P1_THR_12, P1_THR_13, P1_THR_14, P1_THR_15};
    	byte p2ThrMap[16] = {P2_THR_0, P2_THR_1, P2_THR_2, P2_THR_3, P2_THR_4, P2_THR_5,
    							P2_THR_6, P2_THR_7, P2_THR_8, P2_THR_9, P2_THR_10, P2_THR_11,
    							P2_THR_12, P2_THR_13, P2_THR_14, P2_THR_15};
    							
    	pga460::thresholdBulkWrite(p1ThrMap, p2ThrMap);
    	
    	#endif
    }
    
    /*------------------------------------------------- thresholdBulkRead -----
     |  Function thresholdBulkRead
     |
     |  Purpose:  Bulk read all threshold times and levels 
     |
     |  Parameters:
     |		preset (IN) -- which preset's threshold data to read
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::thresholdBulkRead(byte preset)
    {
    	#ifdef EnAutoThr
    	byte n = 0;
    	byte buf15[2] = {syncByte, THRBR};
    	byte presetOffset = 0;
    	byte addr = 0x5F; // beginning of threshold register space
    	
    	switch (comm)
    	{
    		case 0:
    		case 2:
    			if (preset == 2) //Preset 2 advances 16 address bytes
    			{
    				presetOffset = 16;
    			}
    			
    			for (int n = 0; n<16; n++)
    			{
    				bulkThr[n + presetOffset] = registerRead(addr + presetOffset);
    				addr++;
    			}		
    			
    			// Threshold Bulk Read Command 15 too large for Serial1 receive buffer
    			/*Serial1.write(buf15, sizeof(buf15));
    			delay (300);
    			while (Serial1.available() > 0)
    			{
    				bulkThr[n] = Serial1.read();
    				n++;
    			}*/
    			
    			break;
    		
    		case 1: //TCI
    			//TODO
    			break;
    			
    		case 3: //SPI
    			//TODO
    			break;
    		
    		default:
    			break;
    	}
    	#endif
    }
    
    /*------------------------------------------------- thresholdBulkWrite -----
     |  Function thresholdBulkWrite
     |
     |  Purpose:  Bulk write to all threshold registers
     |
     |  Parameters:
     |		p1ThrMap (IN) -- data byte array for 16 bytes of Preset 1 threhsold data
      |		p2ThrMap (IN) -- data byte array for 16 bytes of Preset 2 threhsold data
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::thresholdBulkWrite(byte *p1ThrMap, byte *p2ThrMap)
    {
    	#ifdef EnAutoThr
    	//bulk write new threshold values
    	if ((comm == 0 || comm == 2 || comm==3) && (comm !=6)) 	// USART or OWU mode and not busDemo6
    	{
    		byte buf16[35] = {syncByte,	THRBW, p1ThrMap[0], p1ThrMap[1], p1ThrMap[2], p1ThrMap[3],  p1ThrMap[4], p1ThrMap[5],
    			p1ThrMap[6],  p1ThrMap[7],  p1ThrMap[8], p1ThrMap[9], p1ThrMap[10],   p1ThrMap[11], p1ThrMap[12],
    			p1ThrMap[13], p1ThrMap[14], p1ThrMap[15],
    			p2ThrMap[0],  p2ThrMap[1],  p2ThrMap[2], p2ThrMap[3], p2ThrMap[4],  p2ThrMap[5],
    			p2ThrMap[6],  p2ThrMap[7],  p2ThrMap[8], p2ThrMap[9], p2ThrMap[10], p2ThrMap[11], p2ThrMap[12],
    			p2ThrMap[13], p2ThrMap[14], p2ThrMap[15],
    			calcChecksum(THRBW)};
    		if (comm == 0 || comm == 2) // UART or OWU mode
    		{
    			Serial1.write(buf16, sizeof(buf16)); // serial transmit master data for bulk threhsold
    		}
    		if (comm == 3) // SPI mode
    		{
    			spiTransfer(buf16, sizeof(buf16));
    		}
    		
    	}
    	else if(comm == 6)
    	{
    		return;
    	}
    	else if (comm == 1) // TCI mode
    	{
    		tciIndexRW(5, true); //TCI Threshold Preset 1 write
    		tciIndexRW(6, true); //TCI Threshold Preset 2 write
    	}
    	else
    	{
    		//do nothing
    	}
    	
    	delay(100);
    	return;
    	#endif
    }
    
    /*------------------------------------------------- eepromThreshold -----
     |  Function eepromThreshold
     |
     |  Purpose:  Copy a single preset's threshold times and levels 
     |  			to USER_DATA1-16 in EEPROM
     |
     |  Parameters:
     |		preset (IN) -- preset's threshold to copy
     |		saveLoad (IN) -- when false, copy threshold to EEPROM;
     |					when true, copy threshold from EEPROM
     |
     |  Returns:  none
     *-------------------------------------------------------------------*/
    void pga460::eepromThreshold(byte preset, bool saveLoad)
    {
    	#ifdef EnAutoThr
    	byte presetOffset = 0;
    	byte addr = 0x5F; // beginning of threshold memory space
    	
    	if (saveLoad == false) // save thr
    	{
    		//Preset 2 advances 16 address bytes
    		if (preset == 2 || preset == 4) 
    		{
    			presetOffset = 16;
    		}
    		
    		for (int n = 0; n<16; n++)
    		{
    			bulkThr[n + presetOffset] = registerRead(addr + presetOffset);
    			// write threshold values into USER_DATA1-16
    			registerWrite(n, bulkThr[n + presetOffset]);
    			addr++;
    		}
    	}
    	else // load thr
    	{
    		//Preset 2 advances 16 address bytes
    		if (preset == 2 || preset == 4) //Preset 2 advances 16 address bytes
    		{
    			presetOffset = 16;
    		}
    		
    		// copy USER_DATA1-16 into selected preset threhsold space
    		for (int n = 0; n<16; n++)
    		{
    			bulkThr[n + presetOffset] = registerRead(n);
    			// bulk write to threshold
    			registerWrite(addr + presetOffset, bulkThr[n + presetOffset]);
    			addr++;
    		}
    	}
    	#endif
    }
    
    /*------------------------------------------------- FUNCTION_NAME -----
     |  Function FUNCTION_NAME
     |
     |  Purpose:  EXPLAIN WHAT THIS FUNCTION DOES TO SUPPORT THE CORRECT
     |      OPERATION OF THE PROGRAM, AND HOW IT DOES IT.
     |
     |  Parameters:
     |      parameter_name (IN, OUT, or IN/OUT) -- EXPLANATION OF THE
     |              PURPOSE OF THIS PARAMETER TO THE FUNCTION.
     |                      (REPEAT THIS FOR ALL FORMAL PARAMETERS OF
     |                       THIS FUNCTION.
     |                       IN = USED TO PASS DATA INTO THIS FUNCTION,
     |                       OUT = USED TO PASS DATA OUT OF THIS FUNCTION
     |                       IN/OUT = USED FOR BOTH PURPOSES.)
     |
     |  Returns:  IF THIS FUNCTION SENDS BACK A VALUE VIA THE RETURN
     |      MECHANISM, DESCRIBE THE PURPOSE OF THAT VALUE HERE.
     *-------------------------------------------------------------------*/

    PGA460_USSC.h

    /*
    	PGA460_USSC.h
    	
    	BSD 2-clause "Simplified" License
    	Copyright (c) 2017, Texas Instruments
    	All rights reserved.
    
    	Redistribution and use in source and binary forms, with or without
    	modification, are permitted provided that the following conditions are met:
    
    	1. Redistributions of source code must retain the above copyright notice, this
    	   list of conditions and the following disclaimer.
    	2. Redistributions in binary form must reproduce the above copyright notice,
    	   this list of conditions and the following disclaimer in the documentation
    	   and/or other materials provided with the distribution.
    
    	THIS SOFTWARE IS PROVIDED BY TEXAS INSTRUMENTS "AS IS" AND
    	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    	DISCLAIMED. IN NO EVENT SHALL TEXAS INSTRUMENTS BE LIABLE FOR
    	ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    	The views and conclusions contained in the software and documentation are those
    	of the authors and should not be interpreted as representing official policies,
    	either expressed or implied, of the FreeBSD Project.
    	
    	Last Updated: Nov 2017
    	By: A. Whitehead <make@energia.nu>
    */
     
    #include <Energia.h>
    #include <string.h>
    
    class pga460
    {
      public:
    	pga460();
    	byte pullEchoDataDump(byte element);
    	byte registerRead(byte addr);
    	byte registerWrite(byte addr, byte data);
    	void initBoostXLPGA460(byte mode, uint32_t baud, byte uartAddrUpdate);
    	void defaultPGA460(byte xdcr);
    	void initThresholds(byte thr);
    	void initTVG(byte agr, byte tvg);
    	void ultrasonicCmd(byte cmd, byte numObjUpdate);
    	void runEchoDataDump(byte preset);
    	void broadcast(bool eeBulk, bool tvgBulk, bool thrBulk);
    	void toggleLEDs(bool ds1State, bool fdiagState, bool vdiagState);
    	void autoThreshold(byte cmd, byte noiseMargin, byte windowIndex, byte autoMax, byte avgLoops);
    	void eepromThreshold(byte preset, bool saveLoad);
    	void thresholdBulkRead(byte preset);
    	void thresholdBulkWrite(byte p1ThrMap[], byte p2ThrMap[]);
    	bool burnEEPROM();
    	bool pullUltrasonicMeasResult(bool busDemo);
    	double printUltrasonicMeasResult(byte umr);
    	byte printUltrasonicMeasResultRaw(byte umr);
    	double printUltrasonicMeasResultExt(byte umr, int speedSound);
    	double runDiagnostics(byte run, byte diag);
    	double triangulation(double a, double b, double c);
    	String pullEchoDataDumpBulk();
    
      private:
    	byte calcChecksum(byte cmd);
    	void pga460SerialFlush();
    	void tciRecord(byte numObj);
    	void tciByteToggle(byte data, byte zeroPadding);
    	void tciIndexRW(byte index, bool write);
    	void tciCommand(byte cmd);
    	void spiTransfer(byte* mosi, byte size);
    	void spiMosiIdle(byte size);
    };

    PGA460_SPI.h

    /*
     * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
     * SPI Master library for arduino.
     *
     * This file is free software; you can redistribute it and/or modify
     * it under the terms of either the GNU General Public License version 2
     * or the GNU Lesser General Public License version 2.1, both as
     * published by the Free Software Foundation.
     *
     * 2012-04-29 rick@kimballsoftware.com - added msp430 support.
     *
     */
    
    #ifndef _SPI_H_INCLUDED
    #define _SPI_H_INCLUDED
    
    #include <Energia.h>
    #include <inttypes.h>
    
    #if defined(__MSP430_HAS_USI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_EUSCI_B0__)
    #include "utility/pga460_spi_430.h"
    #endif
    
    #define SPI_MODE0 0
    #define SPI_MODE1 1
    #define SPI_MODE2 2
    #define SPI_MODE3 4
    
    class SPIClass {
    public:
      inline static uint8_t transfer(uint8_t _data);
    
      // SPI Configuration methods
    
      inline static void begin(); // Default
      inline static void end();
    
      inline static void setBitOrder(uint8_t);
      inline static void setDataMode(uint8_t);
      inline static void setClockDivider(uint8_t);
    
      inline static void attachInterrupt();
      inline static void detachInterrupt();
    };
    
    extern SPIClass usscSPI;
    
    uint8_t SPIClass::transfer(uint8_t _data) {
        //return spi_send_pga460(_data);
    }
    
    void SPIClass::begin()
    {
        //spi_initialize_pga460();
    }
    
    void SPIClass::end()
    {
        //spi_disable_pga460();
    }
    
    void SPIClass::setBitOrder(uint8_t bitOrder)
    {
        //spi_set_bitorder_pga460(bitOrder);
    }
    
    void SPIClass::setDataMode(uint8_t mode)
    {
        //spi_set_datamode_pga460(mode);
    }
    
    void SPIClass::setClockDivider(uint8_t rate)
    {
        //spi_set_divisor_pga460(rate);
    }
    
    void SPIClass::attachInterrupt() {
        /* undocumented in Arduino 1.0 */
    }
    
    void SPIClass::detachInterrupt() {
        /* undocumented in Arduino 1.0 */
    }
    
    
    #endif

    PGA460_SPI.h

    /*
     * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
     * SPI Master library for arduino.
     *
     * This file is free software; you can redistribute it and/or modify
     * it under the terms of either the GNU General Public License version 2
     * or the GNU Lesser General Public License version 2.1, both as
     * published by the Free Software Foundation.
     *
     * 2012-04-29 rick@kimballsoftware.com - added msp430 support.
     *
     */
    
    #include "PGA460_SPI.h"
    
    SPIClass usscSPI;

     

  • Tekomoro,

    Have you probed the UART TXD and RXD pins to ensure the PGA460 is both physically receiving the command and responding to the commands?

    Note, the PGA460 requires a minimum of 6V at the VPWR pin supply. However, you should be able to use 5V at VPWR for 3.3V logic level communication debug.

  • Thank You Akeem,

    unfortunately, i don't have access to such a device to do this.

    I tried connecting the module to 12v power, the reading came back to be always 3.96 m and never changes whatever object distance is

    OUTPUT (With the same configurations from before):

    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0
    P1 Obj1 Distance (m): 3.96
    THR_CRC_ERR: 10000100
    DATADUMP_EN: 0

    Any Suggestions?

  • Tekomoro,

    Based on this result, you have not successfully written to the threshold registers. I assume your readout of "THR_CRC_ERR: 10000100" is actually "DEV_STAT0: 10000100" in which case bit-2 is THR_CRC_ERR, which is a value of '1', meaning there is still an error.

    You need to perform a successful threshold bulk write (UART command 16) or a series of single register writes (UART command 10) to the threshold registers (address range 0x5F-0x7E) to clear this THR_CRC_ERR.

    Use the GUI's Interface-->SPI page to generate the correct raw UART command values with a generated checksum based on UART_ADDR and input data. You do not need the actual EVM hardware to run the GUI to use this feature.

  • Akeem Whitehead said:

    Tekomoro,

    Based on this result, you have not successfully written to the threshold registers. I assume your readout of "THR_CRC_ERR: 10000100" is actually "DEV_STAT0: 10000100" in which case bit-2 is THR_CRC_ERR, which is a value of '1', meaning there is still an error.

    You need to perform a successful threshold bulk write (UART command 16) or a series of single register writes (UART command 10) to the threshold registers (address range 0x5F-0x7E) to clear this THR_CRC_ERR.

    Use the GUI's Interface-->SPI page to generate the correct raw UART command values with a generated checksum based on UART_ADDR and input data. You do not need the actual EVM hardware to run the GUI to use this feature.

    I don't think that this is the problem, I tried again the 1 in the THR_CRC_ERR Bit disappeared but it still gives me the same no object

    Here What i did (with 12v supply to the PGA..),

    1:

    PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can bPGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510
    --- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.
    --- To reset the program, and re-prompt for user input, enter a value of 'q'.
    --- To pause/resume the program when running, enter a value of 'p'.
    1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... 0
    2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... 5
    3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... 0
    4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... 0
    5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... 0
    6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... 0
    7. Minimum Distance = 0.1m * BYTE ... 1
    8. Run System Diagnostics?: 0=No, 1=Yes ... 1
    9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... 0
    10. Burn/Save User EEPROM?: 0=No, 1=Yes ... 0
    11. Command Cycle Delay: 100ms * BYTE ... 2
    12. Number of Objects to Detect (1-8) = BYTE ... 1
    13. USART Address of PGA460 (0-7) = BYTE ... 0
    Configuring the PGA460 with the selected settings. Wait...
    System Diagnostics - Frequency (kHz): 41.67
    System Diagnostics - Decay Period (us): 4080.00
    System Diagnostics - Die Temperature (C): 34.67
    System Diagnostics - Noise Level: 0.00
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...


    2:
    PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510
    --- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.
    --- To reset the program, and re-prompt for user input, enter a value of 'q'.
    --- To pause/resume the program when running, enter a value of 'p'.
    1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... 0
    2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... 5
    3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... 0
    4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... 72
    5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... 72
    6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... 72
    7. Minimum Distance = 0.1m * BYTE ... 1
    8. Run System Diagnostics?: 0=No, 1=Yes ... 1
    9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... 0
    10. Burn/Save User EEPROM?: 0=No, 1=Yes ... 0
    11. Command Cycle Delay: 100ms * BYTE ... 2
    12. Number of Objects to Detect (1-8) = BYTE ... 4
    13. USART Address of PGA460 (0-7) = BYTE ... 0
    Configuring the PGA460 with the selected settings. Wait...
    System Diagnostics - Frequency (kHz): 41.67
    System Diagnostics - Decay Period (us): 4080.00
    System Diagnostics - Die Temperature (C): 37.33
    System Diagnostics - Noise Level: 0.00
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...
    THR_CRC_ERR: 10000000
    DATADUMP_EN: 0
    No object...

    Do you think the problem is Tivac related or sensor related?

  • Tekomoro,

    Based on your system diagnostic results, you are now successfully bursting-and-listening, so I think your issue is either sensor based or you need to optimize the PGA460 driver/receiver settings. Your Tiva UART interface code appears to be working.

    First, what is the frequency of your transducer? Your system diagnostic frequency result is reporting a captured value of 41.67kHz, but you have selected case #4's Transducer Settings: 0=Murata MA58MF14-7N (58.5kHz) in the first run, and skipped the transducer frequency setting in the second run, which means it is likely defaulting to the factory value of 58.5kHz if you've never EEPROM programmed the PGA460.

    As a quick test, you can change case # 4. Transducer Settings to 1=Murata MA40H1S-R for 40kHz operation to see if you get different results.

    It is important to understand what the echo data dump (EDD) output looks like in comparison to the threshold level also. You should run the case #9 Echo Data Dump at 1=P1BL and 2=P2BL to get the echo envelope output values. Your questions are becoming more PGA460 parameter specific, so I recommend you view this video series to better understand and be able to optimize the driver, receiver, and threshold values: https://training.ti.com/ultrasonic-sensing-pga460-q1 . Without proper optimiziation, you may never detect an object as in your last cases.

  • Thank You Akeem,

    I tried setting case #4 and #9,

    I got wrong values for distance almost all the time and the THR_CRC_ERR bit returned to 1 and i don't know how to decide the right values for thresholds to overcome the error

    also, is there any way to decide right values for TVG Range and Fixed TVG Level ?

    Thank You,

    Here The whole output,

    PGA460-Q1 EVM UART/TCI/OWU/SPI Energia Demo for Ultrasonic Time-of-Flight
    -------------------------------------------------------------------------
    Instructions: Configure the EVM by entering a byte value between 0-9 or 'x' per request.
    --- Input can be entered as a single string to auto-increment/fill each request. E.g. 0011211000510
    --- To skip the COM setup at any point, and use the hard-coded values from thereon, enter a value of 's'.
    --- To reset the program, and re-prompt for user input, enter a value of 'q'.
    --- To pause/resume the program when running, enter a value of 'p'.
    1. Communication Mode: 0=UART, 1=TCI, 2=OneWireUART, 3=SPI ... 0
    2. UART kBaud: 0=9.6, 1=19.2, 2=38.4, 3=57.6, 4=74.8, 5=115.2 ... 0
    3. P1 and P2 Thresholds: 0=%25, 1=50%, or 2=75% of max ... 0
    4. Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R, x=Skip ... 1
    5. TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB, x=Skip ... 72
    6. Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max, x=Skip ... 1
    7. Minimum Distance = 0.1m * BYTE ... 1
    8. Run System Diagnostics?: 0=No, 1=Yes ... 1
    9. Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO,... 1
    10. Burn/Save User EEPROM?: 0=No, 1=Yes ... 0
    11. Command Cycle Delay: 100ms * BYTE ... 2
    12. Number of Objects to Detect (1-8) = BYTE ... 1
    13. USART Address of PGA460 (0-7) = BYTE ... 0
    Configuring the PGA460 with the selected settings. Wait...
    System Diagnostics - Frequency (kHz): 10.99
    System Diagnostics - Decay Period (us): 2608.00
    System Diagnostics - Die Temperature (C): 66.00
    System Diagnostics - Noise Level: 54.00
    Retrieving echo data dump profile. Wait...
    ,251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,203,179,172,161,136,106,79,57,39,24,14,10,12,14,18,24,29,30,29,22,18,25,28,28,25,20,16,11,7,7,11,14,15,15,13,12,11,10,10,9,9,9,9,10,10,9,7,5,5,5,6,5,4,2,3,4,4,4,2,2,1,1,1,1,2,2,2,2,3,4,5,5,5,3,2,3,3,3,3,3,2,2,1,2,2,2,2,2,3,3,3,3,3,3,3,3,2,3,3,4,5,4,4,4,231
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 5.22
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 6.60
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 0.97
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 6.60
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 8.73
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 9.44
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 5.92
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 2.41
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 2.39
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 1.00
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 8.03
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 10.11
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 2.41
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 0.99
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 5.21
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 10.11
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 8.72
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 1.70
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 3.09
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P1 Obj1 Distance (m): 9.42
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 0.98
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    P2 Obj1 Distance (m): 0.30
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110
    No object...
    THR_CRC_ERR: 11110111
    DATADUMP_EN: 11110110

  • Another thing,

    whenever i try to write to EEPROM it always fails

  • Hi Tekomoro,

    Have you viewed the https://training.ti.com/ultrasonic-sensing-pga460-q1 video series? Based on your questions, it is important for you to view this video to see a demonstration on how to set the threshold and time varying gain values.

    The PGA460-Q1 EVM and GUI combination would help you to quickly optimize the threshold and time varying gain values, but you can create a similar preview by uploading the echo data dump from Energia into the GUI. You do not need to have the EVM connected to use the GUI's DeviceSettings-->Threshold-->LoadChart feature. This way, you can import any echo data dump, and map the threshold time and levels to optimize the settings. You'll need to manually convert the time and level values to the bit level Px_THR_n values since you do not have the EVM hardware. This same process applies to the time varying gain.

    How are you powering the PGA460? If the VPWR supply is dropping below the minimum VPWR required voltage of 6V (during burst), it is possible for the volatile memory to reset, which includes the threshold values, and the THR_CRC_ERR flag returns high. Try using a larger VPWR voltage, or add additional bulk capacitance at the VPWR pin to maintain the voltage during the transducer driver/burst window.

    You cannot write directly to EEPROM, but it is possible to save all shadow register values (address 0x00-0x2B) into EEPROM by implementing an EEPROM burn routine, which is the function called by step "10. Burn/Save User EEPROM?" of the Energia sketch. This routine has very specific timing requirements as indicated in datasheet section:

    7.6.1 EEPROM Programming
    To program the EEPROM, follow these steps:

    1. Send an EEPROM program command using UART or TCI with a unique unlock pattern on 4-bits. The program bit is set to 0 in register 0x40. The unlock passcode is 0x Dh.

    2. Immediately send the same UART or TCI command with the program bit set to 1.

    If any other command is issued after the unlock code (Step 1), the EEPROM program is initiated. Also, if the unlock command in Step 1 is not correct, the EEPROM is not programmed. The EEPROM is locked again automatically after each program command.

    NOTE: This EEPROM passcode is applicable by communication in the UART mode and for TCI mode done through Config command 11.

  • Hi Tekomoro,

    Also, since you have the PGA460PSM-EVM, you can simply purchase the MSP-EXP430F5529LP LaunchPad to enable use of the PGA460-Q1 EVM GUI. You'll only need to connect the UART pins (TXD and RXD) and have a common ground between the LaunchPad and PGA460PSM-EVM. You'll need to supply the PGA460PSM-EVM with an external supply between 6-28V as you are today.

  • Thank You Akeem,

    I did view the videos more than once but still can't use the GUI because I don't have the MSP-EXP430F5529LP so, I have only the Energia Sofware options:

    Transducer Settings: 0=Murata MA58MF14-7N, 1=Murata MA40H1S-R
    TVG Range: 0=32-64dB, 1=46-78dB, 2=52-84dB, or 3=58-90dB
    Fixed TVG Level: 0=%25, 1=50%, or 2=75% of max
    Minimum Distance
    Run System Diagnostics?: 0=No, 1=Yes
    Echo Data Dump: 0=None, 1=P1BL, 2=P2BL, 3=P1LO, 4=P2LO
    Burn/Save User EEPROM?
    Command Cycle Delay
    Number of Objects to Detect
    USART Address of PGA460

    For power, I am still using the same 12v battery

    This is the result of plotting the data dump,

    And this is data dump for the available 4 options:

    P1BL:

    251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,209,111,67,52,38,22,15,13,11,8,6,14,35,66,90,100,100,93,78,64,50,40,30,26,21,19,23,24,27,31,35,35,34,29,25,21,18,16,12,10,11,11,11,13,14,15,16,16,16,14,12,9,6,5,4,3,3,4,4,6,7,8,8,8,6,5,4,4,3,2,3,3,3,3,3,4,4,4,4,2,2,2,2,2,3,3,3,2,2,2,3,3,4,4,4,4,4,3,3,3,3,4,4,4,4,4,4,48

    P2BL:

    255,255,255,255,103,32,32,32,24,23,23,20,16,9,4,5,5,9,9,7,2,3,3,6,6,4,3,3,4,5,5,3,6,6,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,3,3,4,2,4,3,4,4,3,3,4,5,5,3,3,3,2,3,3,4,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,4,4,3,3,3,3,3,3,3,3,2,3,4,3,3,3,2,2,3,3,3,3,3,3,3,3,3,3,1

    P1LO:

    6,12,88,176,96,96,96,192,192,129,2,2,2,2,2,2,2,2,1,1,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,4,4,4,3,3,3,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,3,2,2,3,4,4,4,4,4,4,3,3,3,2,2,2,2,1,2,2,3,3,3,3,3,3,3,3,3,3,3,3,2,3,4,4,4,3,3,3,3,3,3,3,3,3,3,3

    P2LO:
    38,76,152,48,96,96,96,96,96,96,96,193,130,3,3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,3,4,4,3,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,4,3,3,3,3,4,4,3,4,4,4,3,3,3,3,3,3,3,3,3,3,3,4,3,4,4,3,4,4,3,4,4,3,4,3,3,3,4,3,3,3,3,4,4,3,3,3,4,4,4,3,3,3,4,3,3,3,3,3,4,3


    I don't have the BoostXL-PGA460 BoosterPack, I just have the TivaC and the PGA460PSM-EVM

    What should I have to run the GUI beside what I have, is it the MSP-EXP430F5529LP,  BoostXL-PGA460 BoosterPack OR Both?

    it will take a long time to get them here in Egypt (a month at least), till then, can I do anything else with what I have?

  • Tekemoro,

    Here is a step-by-step guide on using the GUI's threshold page without the actual EVM hardware to help optimize the threshold time and levels:

    1) Convert the echo data dump output from the Energia sketch into the GUI compatible text format. Here is an attached example of your P1BL echo data dump output string converted to the GUI's echo data dump text file template: 

    E2E-862350_P1BL.txt
    ;EDD
    0,0,251,
    1,0.064,255,
    2,0.128,255,
    3,0.192,255,
    4,0.256,255,
    5,0.32,255,
    6,0.384,255,
    7,0.448,255,
    8,0.512,255,
    9,0.576,255,
    10,0.64,255,
    11,0.704,255,
    12,0.768,255,
    13,0.832,255,
    14,0.896,255,
    15,0.96,255,
    16,1.024,255,
    17,1.088,255,
    18,1.152,255,
    19,1.216,255,
    20,1.28,209,
    21,1.344,111,
    22,1.408,67,
    23,1.472,52,
    24,1.536,38,
    25,1.6,22,
    26,1.664,15,
    27,1.728,13,
    28,1.792,11,
    29,1.856,8,
    30,1.92,6,
    31,1.984,14,
    32,2.048,35,
    33,2.112,66,
    34,2.176,90,
    35,2.24,100,
    36,2.304,100,
    37,2.368,93,
    38,2.432,78,
    39,2.496,64,
    40,2.56,50,
    41,2.624,40,
    42,2.688,30,
    43,2.752,26,
    44,2.816,21,
    45,2.88,19,
    46,2.944,23,
    47,3.008,24,
    48,3.072,27,
    49,3.136,31,
    50,3.2,35,
    51,3.264,35,
    52,3.328,34,
    53,3.392,29,
    54,3.456,25,
    55,3.52,21,
    56,3.584,18,
    57,3.648,16,
    58,3.712,12,
    59,3.776,10,
    60,3.84,11,
    61,3.904,11,
    62,3.968,11,
    63,4.032,13,
    64,4.096,14,
    65,4.16,15,
    66,4.224,16,
    67,4.288,16,
    68,4.352,16,
    69,4.416,14,
    70,4.48,12,
    71,4.544,9,
    72,4.608,6,
    73,4.672,5,
    74,4.736,4,
    75,4.8,3,
    76,4.864,3,
    77,4.928,4,
    78,4.992,4,
    79,5.056,6,
    80,5.12,7,
    81,5.184,8,
    82,5.248,8,
    83,5.312,8,
    84,5.376,6,
    85,5.44,5,
    86,5.504,4,
    87,5.568,4,
    88,5.632,3,
    89,5.696,2,
    90,5.76,3,
    91,5.824,3,
    92,5.888,3,
    93,5.952,3,
    94,6.016,3,
    95,6.08,4,
    96,6.144,4,
    97,6.208,4,
    98,6.272,4,
    99,6.336,2,
    100,6.4,2,
    101,6.464,2,
    102,6.528,2,
    103,6.592,2,
    104,6.656,3,
    105,6.72,3,
    106,6.784,3,
    107,6.848,2,
    108,6.912,2,
    109,6.976,2,
    110,7.04,3,
    111,7.104,3,
    112,7.168,4,
    113,7.232,4,
    114,7.296,4,
    115,7.36,4,
    116,7.424,4,
    117,7.488,3,
    118,7.552,3,
    119,7.616,3,
    120,7.68,3,
    121,7.744,4,
    122,7.808,4,
    123,7.872,4,
    124,7.936,4,
    125,8,4,
    126,8.064,4,
    127,8.128,48,
    
    EOF
    

    You will need to convert your other echo data dump captures to match this text file format exactly. You will need to know your record time to set the time interval correctly. Using the Energia's default transducer settings for the Murata MA40H1S-R, preset 1 will be set to a record length of 8.192ms.

    2) Use the threshold page's "Load Chart" feature, and import the GUI compatible echo data dump text file. Here is your P1BL data dump (yellow), and a fixed threshold I have set based on what I assume is your object at approximately 2ms (or 34cm).

    Notice I do not have the EVM hardware connected, because it is not required to utilize this feature.

    3) Finally, you will need to convert the threhsold time and level values into the bit values for the Px_THR_y registers. This is the most challenging part to do without the actual EVM hardware, because the GUI needs to be able to read/write to the actual device to generate these values on the Memory Map page. You would then port these threshold values into the PGA460 Energia library's PGA460_USSC.cpp file as another switch-case statement to create a custom threshold option.

    Regarding your question about actually running the GUI, you only need to order the MSP-EXP430F5529LP since you already have a PGA460PSM-EVM. You will need to simply jump wire the UART pins (TXD and RXD) from the LaunchPad to the EVM to use the GUI.