Firmware for Nucleo boards for the SLab system Description at http://r6500.blogspot.com.es/2018/02/slab-first-release.html All associated files at https://github.com/R6500/SLab

Dependencies:   mbed

main.cpp

Committer:
vic20
Date:
2018-02-10
Revision:
0:39a545e08ccd
Child:
1:d81bef65eece

File content as of revision 0:39a545e08ccd:

/*******************************************************

  SLab - Python 
  
  MBED Firmware for Nucleo Boards
  Alternate version for profiling
  
  Program to operate a nucleo board from a PC
  in order to perform measurements.
  
  Desgined for the Nucleo64 F303RE Board

  Commands implemented in version 1
  
  Global
  
  F     : Obtain a string that describes the firmware
  M     : Obtain 4 byte magic code
  I     : Board capabilities identification
  L     : Pin list
  E     : Soft Reset
  
  DC
  
  A + 1 : Read one ADC channel
  D + 3 : Write one DAC channel
  N + 2 : Set number of reads to average

  
  Transient
  
  R + 2 : Set sample time
  S + 4 : Set storage configuration
  Y     : Async read
  G + 3 : Triggered read
  P + 2 : Step response
  
  Wavetable
  
  W + n : Load a wavetable
  w + n : Load a secondary wavetable
  V + 2 : Wave response
  v + 2 : Dual wave response
  X + 3 : Single Wave Response
  Q + 2 : Wave Play
  q + 2 : Dual Wave Play
    
  Digital I/O
  
  H + 2 : dio mode
  J + 2 : dio write
  K + 1 : dio read  
     
Incidences:

  06/04/2017 : Open Drain does not work as expected
               It is currently disabled    
               
  25/10/2017 : v1.1
               Hardware profile lines added
               Improved timings. Minimum sample times:
                 Asyn Read: 1CH (13us) 2CH (33us)  3CH (43us) 4CH (54us)
                 Trig Read: 1CH (13us) 2CH (33us)  3CH (44us) 4CH (54us)
                 Step Resp: 1CH (13us) 2CH (36us)  3CH (46us) 4CH (56us)
                 Wave Resp: 1CH (13us) 2CH (38us)  3CH (47us) 4CH (58us)
                 Dual Wave: 1CH (13us) 2CH (40us)  3CH (50us) 4CH (61us)
                 Sing Wave: 1CH Only (13us)   
                 Wave play: No ADC (11us)  
                 Dual wave play: No ADC (11us)      
     
********************************************************/

#include "mbed.h"

/***************** MAIN DEFINES *************************************/

// Version string
#define VSTRING " v1.1"

// Major number version changes when new commands are added
#define VERSION 1

// Uncomment to use hardware profiling during tests
// It should be commented for release versions
//#define USE_PROFILING 1

// Information about the board
#include "Nucleo64-F303RE.h"  // Board 1
//#include "Nucleo32-F303K8.h"  // Board 2
//#include "Nucleo64-L152RE.h"  // Board 3

/******************* OTHER CONSTANTS ******************************/

// Max value in unsigned 16bit as float number
#define MAX16F 65536.0f 

// Special serial codes
#define ACK  181
#define NACK 226
#define ECRC 37

// Codes for transient responses
#define TRAN_OK       0  // Ok
#define TRAN_OVERRUN  1  // Sample overrun
#define TRAN_TIMEOUT  2  // Triggered timeout

// Magic data is different for each firmware
#define MAGIC_SIZE 4
const uint8_t magic[MAGIC_SIZE]={56,41,18,1};

/***************** VARIABLES AND OBJECTS *************************/

Serial pc(SERIAL_TX, SERIAL_RX, 38400);   // Serial link with PC

AnalogIn   ain1(AD1);
AnalogIn   ain2(AD2);
AnalogIn   ain3(AD3);
AnalogIn   ain4(AD4);

AnalogIn   *ainList[NADCS];

AnalogOut  aout1(DA1);   // DAC1
AnalogOut  aout2(DA2);   // DAC2 
#ifdef EXIST_DAC3
AnalogOut  aout3(DA3);   // DAC3 if exists
#endif 

#ifdef EXIST_DIO  // For now, it requires 8 DIO
DigitalInOut dio1(DIO1);
DigitalInOut dio2(DIO2);
DigitalInOut dio3(DIO3);
DigitalInOut dio4(DIO4);
DigitalInOut dio5(DIO5);
DigitalInOut dio6(DIO6);
DigitalInOut dio7(DIO7);
DigitalInOut dio8(DIO8);

DigitalInOut *dioList[NDIO];
#endif

// Sample time period defaults to 1ms
float stime = 0.001;

// Buffer for storage of inputs (in U16)
//uint16_t inBuff[IN_BSIZE];

// Wavetable buffer (in U16)
//uint16_t waveBuff[WSIZE];

// Unified memory buffer
uint16_t buff[BSIZE];

// Start of all buffer sections
uint16_t *wave2buff = NULL;
uint16_t *tranBuff  = NULL;

// DC analog read number of readings
int nread = 10;

// Input configuration
int n_ai = 1;     // Number of analog inputs
int n_di = 0;     // Number of digital inputs (always zero)
int n_s  = 1000;  // Number of samples

// Ticker for readings
Ticker ticR;

// Sample information for ticker
int samples = 0;    // Number of processed samples
int inBuffPos = 0;  // Current buffer position

int presamples;     // Number of samples before trigger
int postsamples;    // Number of samples after trigger
int triggerSample;  // Sample number at trigger point
int samplePhase;    // Sample phase
int currentBsize;   // Current buffer size
int trigger;        // Trigger value
int triggerMode;    // Trigger mode (0 Rise 1 Fall)
int stepValue;      // Value for step analysis

int checkTimeOut;   // Indicates if we check timeout
uint32_t timeOut;   // Timeout for triggered capture

// Global to communicate with ISR ticker
volatile int endTicker = 0;

// Global to check overruns
volatile int overrun = 0;
volatile int overrun_error = 0;
volatile int timeout_error = 0;

int w_s = 0;             // Wavetable size (in samples)
volatile int w_n = 10;   // Number of waves before measurement
volatile int w_pos = 0;  // Current wave position

int w_s2 = 0;            // Secondary wavetable size (in samples)
volatile int w_pos2 = 0; // Current secondary wave position

// Globals for CRC
int crcTx,crcRx;

// Selected ADC for transient
AnalogIn *ain_tran;

// Indicate that board status is at reset condition
int resetState=1;

/****************** HARDWARE PROFILING *********************************/
// Uses GPIO lines to show system activity

#ifdef USE_PROFILING

// Profiling outputs
DigitalOut pro1(PRO1_PIN);
DigitalOut pro2(PRO2_PIN);

#else

#define PRO1_SET    /* No code */
#define PRO1_CLEAR  /* No code */
#define PRO2_SET    /* No code */
#define PRO2_CLEAR  /* No code */ 

#endif //USE_PROFILING

/*********************** SERIAL CODE **********************************/

// Start Tx
// Clears the tx crc
void startTx()
 {
 crcTx = 0;
 }
 
// Send Tx CRC
// Usually that ends transmission
void sendCRC()
 {
 pc.putc(crcTx);
 }     
 
// Send one byte and computes crc
void sendByte(int value)
 {
 pc.putc(value);
 crcTx = crcTx ^ value;    
 }    
 
// Send one uint16 and computes crc
void sendU16(int value)
 {
 int low,high;    
 
 high = value / 256;
 low  = value % 256;
      
 sendByte(low);
 sendByte(high);    
 }    
      
// Send float as mantisa and exponent
void sendMantExp(int mantissa, int exponent)
 {
 sendByte(exponent+128);
 sendU16(mantissa+20000);    
 }     
      
// Send one string and computes crc
void sendString(char *str)
 {
 while (*str)
    {
    sendByte(*str); 
    str++;
    }
 }          

// Start of a Rx reception
void startRx()
 { 
 crcRx = 0;
 }    
 
 
// Get CRC anc check it
// It usually ends the Rx reception
// Returns 1 if CRC is ok, 0 if not
int getAndCheckCRC()
 {
 int crc;
 
 crc = pc.getc();
 if (crc != crcRx) return 0;
 return 1;
 }
 
// Get and check CRC and sends ECRC in case of error
// If no error, don't respond anything
// Returns 1 if CRC is ok, 0 if not
int crcResponse()
 {
 // Check if CRC is ok    
 if (getAndCheckCRC()) return 1;
 
 // If CRC is not ok
 sendByte(ECRC);  
 // End transmission
 sendCRC();
 return 0;    
 }    

   
// Get one byte and computes crc
int getByte()
 {
 int byte;
 
 byte = pc.getc();
 crcRx = crcRx ^byte;
 return byte;   
 }

    
// Get one uint16 and computes crc
int getU16()
 {
 int low, high, value;
 
 low  = getByte();
 high = getByte();
 value = (256 * high) + low;
 
 return value;   
 }   


// Get one float value and computes crc
float getFloat()
 {
 int exp,mant;
 float value; 
 
 exp = getByte() - 128;
 mant = getU16() - 20000;
 
 value = ((float)mant) * pow((float)10.0,(float)exp);
 
 return value;    
 }
   
/*********************** DC CODE ********************************/

// Reads one analog line 1...
// Discards the first reading
// Uses the indicated number of readings
static int analogRead(int line)
 {
 int i,value;    
 uint32_t sum;
 
 sum = 0;
 for(i=0;i<=nread;i++) 
    {
    value=ainList[line-1]->read_u16();
    if (i) sum+=value;
    }    
    
 value = sum/nread;   
      
 return value;     
 }    
 
/********************* TRANSIENT CODE ***************************/ 
 
// Calculates available transize
static inline uint16_t tranBuffSize()
 {
 uint16_t size;
 
 size = BSIZE - w_s - w_s2;   
 return size;  
 }  
 
// Calculates available wave 2 buff size
static inline uint16_t wave2buffSize()
 {
 uint16_t size;
 
 size = BSIZE - w_s;   
 return size;  
 }   
 
// Implements command 'R'
// Sets the sample period time
void setSampleTime()
 {
 //Get sample time
 stime = getFloat();
 
 // End of message, check CRC
 if (!crcResponse()) return;
 
 // Check limits
 if ((stime < MIN_STIME) || (stime > MAX_STIME))
      sendByte(NACK);
      else
      sendByte(ACK);
      
 // End of message
 sendCRC();     
 }    

// Implements command 'S'
// Configure storage
void setStorage()
 {
 int sample_size,size; 
 int error = 0;   
          
 // Get number of analog inputs
 n_ai = getByte();
 if (n_ai > 4) error = 1;
 
 // Get number of digital inputs
 // Not implemented yet
 n_di = getByte();
 if (n_di != 0) error = 1;
 
 // Get the number of samples
 n_s = getU16();
 
 // End of message, check CRC
 if (!crcResponse()) return; 
 
 // Check if it fits the buffer
 if (n_di)
    sample_size = n_ai+1;
    else
    sample_size = n_ai;
    
 size = n_s*sample_size;
 if (size > tranBuffSize()) error = 1;
 
 // Response depending on errors
 if (error)
      sendByte(NACK);
      else
      sendByte(ACK);
      
 // End of message
 sendCRC();          
 }    

// Store analog inputs in circular buffer
static inline int storeAnalog()
 {
 int a1; 
     
 a1 = ain1.read_u16();  
  
 if (n_ai >= 1) tranBuff[inBuffPos++]=a1; 
 if (n_ai >= 2) tranBuff[inBuffPos++]=ain2.read_u16();
 if (n_ai >= 3) tranBuff[inBuffPos++]=ain3.read_u16();
 if (n_ai >= 4) tranBuff[inBuffPos++]=ain4.read_u16();
 
 if (inBuffPos == currentBsize) inBuffPos = 0;
 
 return a1;
 }    

// Dumps the input buffer on serial
void dumpInBuffer()
  {
  int ia,is;    
      
  // Response code
  if (overrun_error)
        {
        sendByte(TRAN_OVERRUN);
        return;
        }
        else
        sendByte(TRAN_OK);    
      
  sendByte(n_ai);  // Number of analog    
  sendByte(n_di);  // Number of digital (always zero)
  sendU16(n_s);  // Number of samples
  
  for(ia=0;ia<n_ai;ia++)                // For every analog input
       for(is=0;is<n_s;is++)            // For every sample
       sendU16(tranBuff[is*n_ai+ia]);     // Send it
  }   
  
// Dumps the input buffer on serial
// Overrides the nimber of analog channels and sets it to 1
void dumpInSingleBuffer()
  {
  int is;    
      
  // Response code
  if (overrun_error)
        {
        sendByte(TRAN_OVERRUN);
        return;
        }
        else
        sendByte(TRAN_OK);    
      
  sendByte(1);  // Number of analog is 1   
  sendByte(n_di);  // Number of digital (always zero)
  sendU16(n_s);  // Number of samples
  
  for(is=0;is<n_s;is++)         // For every sample
       sendU16(tranBuff[is]);     // Send it
  }      

/********************* ASYNC READ ***************************/ 

// Hardware profiling operation (if enabled)
//   PRO1 line high during ISR
//   PRO2 line mimics overrun variable

// ISR for the asyncRead function
void asyncReadISR()
 {
 PRO1_SET // Profiling        

 // Store analog data    
 storeAnalog();    
 
 // Increase sample
 samples++;
     
 // Check if we should end
 if (samples >= n_s)
    {
    // Disable ticker
    ticR.detach();     
    // Signal end
    endTicker = 1;
    PRO1_CLEAR // Profiling   
    return;
    }   
    
 // Check for overrun
 if (overrun)
    {
    overrun_error = 1;
    }
    
 overrun = 1;  
 
 PRO2_SET    // Profiling
 PRO1_CLEAR            
 }    
 
// ISR for the asyncRead function
// Optimized timing when only reading one input
// Used only for one input and stime < 25us
void asyncReadSingleISR()
 {
 PRO1_SET // Profiling    
  
 // Direct access to ADC registers 
 ADC1->CR |= ADC_CR_ADSTART;           
 while (!(ADC1->ISR & ADC_ISR_EOC));
 tranBuff[inBuffPos++] = (ADC1->DR)<<4;         
 
 if (inBuffPos == currentBsize) inBuffPos = 0;
 
 // Increase sample
 samples++;
     
 // Check if we should end
 if (samples >= n_s)
    {
    // Disable ticker
    ticR.detach();     
    // Signal end
    endTicker = 1;
    PRO1_CLEAR // Profiling   
    return;
    }   
    
 // Check for overrun
 if (overrun)
    {
    overrun_error = 1;
    }
 overrun = 1;    
 
 PRO2_SET    // Profiling
 PRO1_CLEAR         
 }   

// Implements command 'Y'
// Async read
 // This command don't get any parameter
void asyncRead()
 {    
 PRO1_CLEAR  // Reset profiling lines
 PRO2_CLEAR
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 // Send ACK to command
 sendByte(ACK);
 
 // Configure ticker ISR    
 samples = 0;    // Number of processed samples
 inBuffPos = 0;  // Current buffer position
 endTicker = 0;  // Ticker has not ended
 
 currentBsize = n_ai * n_s;        // Current size for buffer
     
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;   
 PRO2_CLEAR   // Profiling     
     
 // Check if we only read one channel and stime is less than 41us
 if ((n_ai==1)&&(stime<25e-6f))
    {
    // Perform a dummy read
    ain1.read_u16();     
    // Programs the ticker for one input optimized ISR version
    ticR.attach(&asyncReadSingleISR,stime);   
    }
   else     
    { 
    // Programs the ticker for several inputs
    ticR.attach(&asyncReadISR,stime);
    }
 
 // Wait till end
 while (!endTicker) { overrun = 0; PRO2_CLEAR }
 
 // Return data
 dumpInBuffer();  // Dump data
 
 sendCRC(); // End of Tx 
 }
 
/********************* TRIGGERED READ ***************************/ 
 
// Hardware profiling operation (if enabled)
//   PRO1 line high during ISR
//   PRO2 line mimics overrun variable 
 
// Dumps the input buffer on serial for triggered caputure
void dumpTriggeredInBuffer()
  {
  int ia,is,pos,sample,first;    
      
  presamples = n_s/2;               // Number of samples before trigger
  postsamples = n_s - presamples;   // Number of samples after trigger    
  
  // Response code
  if (overrun_error)
        {
        sendByte(TRAN_OVERRUN);
        return;
        }
  
  if (timeout_error)
        {
        sendByte(TRAN_TIMEOUT);    
        return;    
        }
  
  sendByte(TRAN_OK);    
      
  sendByte(n_ai);  // Number of analog    
  sendByte(n_di);  // Number of digital (always zero)
  sendU16(n_s);    // Number of samples
  
  // First sample to send
  first = (triggerSample - presamples + n_s)%n_s;
  
  for(ia=0;ia<n_ai;ia++)                    // For every analog input
       for(is=0;is<n_s;is++)                // For every sample
          {
          sample = (first+is)%n_s;          // Calculate sample
          pos = sample*n_ai+ia;             // Calculate buff position
          sendU16(tranBuff[pos]);            // Send it
          }
  }     
 
// ISR for the triggeredRead function
void triggeredReadISR()
 {
 int a1;    
 
 PRO1_SET
     
 // Store analog data    
 a1 = storeAnalog();    
 
 // Increase sample
 samples++;
 if (samples == n_s) samples = 0;
 
 // Decrease timeout
 timeOut--;
 
 // Check phase
 switch(samplePhase)
    {
    case 0: // Prefill of the buffer
      presamples--;
      if (!presamples) samplePhase = 1;
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }
      break;
    case 1: // Wait for trigger precondition
      if (triggerMode == 0) // Rise
         if (a1 < trigger) samplePhase = 2;
      if (triggerMode == 1) // Fall
         if (a1 > trigger) samplePhase = 2;    
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }   
      break;  
    case 2: // Wait for trigger postcondition
      if (triggerMode == 0) // Rise
         if (a1 > trigger)
                     {
                     samplePhase = 3;
                     triggerSample = samples;
                     }
      if (triggerMode == 1) // Fall
         if (a1 < trigger)
                     {
                     samplePhase = 3;
                     triggerSample = samples;
                     }
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }               
      break;
    case 3: // Capture after trigger
      postsamples--;  
      if (!postsamples) 
            {
            // Disable ticker
            ticR.detach();     
            // Signal end
            endTicker = 1;        
            }
      break;    
    } 
    
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 
 PRO2_SET
 PRO1_CLEAR       
 }    
 
// ISR for the triggeredRead function
// Version optimized for only one channel
// Only used for single channel and stime < 30us
void triggeredReadSingleISR()
 {
 int a1;    
 
 PRO1_SET
     
 // Direct access to ADC registers 
 ADC1->CR |= ADC_CR_ADSTART;           
 while (!(ADC1->ISR & ADC_ISR_EOC));
 a1=(ADC1->DR)<<4;
 tranBuff[inBuffPos++]=a1;  
 
 if (inBuffPos == currentBsize) inBuffPos = 0;   
 
 // Increase sample
 samples++;
 if (samples == n_s) samples = 0;
 
 // Decrease timeout
 timeOut--;
 
 // Check phase
 switch(samplePhase)
    {
    case 0: // Prefill of the buffer
      presamples--;
      if (!presamples) samplePhase = 1;
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }
      break;
    case 1: // Wait for trigger precondition
      if (triggerMode == 0) // Rise
         if (a1 < trigger) samplePhase = 2;
      if (triggerMode == 1) // Fall
         if (a1 > trigger) samplePhase = 2;    
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }   
      break;  
    case 2: // Wait for trigger postcondition
      if (triggerMode == 0) // Rise
         if (a1 > trigger)
                     {
                     samplePhase = 3;
                     triggerSample = samples;
                     }
      if (triggerMode == 1) // Fall
         if (a1 < trigger)
                     {
                     samplePhase = 3;
                     triggerSample = samples;
                     }
      if (!timeOut)
        {
        // Set error
        timeout_error = 1;
        // Disable ticker
        ticR.detach();     
        // Signal end
        endTicker = 1;
        }               
      break;
    case 3: // Capture after trigger
      postsamples--;  
      if (!postsamples) 
            {
            // Disable ticker
            ticR.detach();     
            // Signal end
            endTicker = 1;        
            }
      break;    
    } 
    
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 
 PRO2_SET
 PRO1_CLEAR       
 }   
 
// Implements command 'G'
// Triggered read
void triggeredRead()
 {    
 PRO1_CLEAR  // Reset profiling lines
 PRO2_CLEAR
 
 // Get trigger point
 trigger = getU16();
 // Get trigger mode
 triggerMode = getByte();
 // Get timeout in seconds
 timeOut = getByte();
 
 if (timeOut)
    {
    checkTimeOut=1;
    // Convert to samples
    timeOut=int(1.0*timeOut/stime);
    }
    else
    checkTimeOut = 0;
 
 // Erase timeout error
 timeout_error = 0;
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 // Check mode
 if ( (triggerMode != 0) && (triggerMode != 1) )
    {
    sendByte(NACK);
    sendCRC();
    return;
    }
    
 // All ok
 sendByte(ACK);   
 
 // Configure ticker ISR    
 samples = 0;    // Number of processed samples
 inBuffPos = 0;  // Current buffer position
 endTicker = 0;  // Ticker has not ended
 
 presamples = n_s/2;               // Number of samples before trigger
 postsamples = n_s - presamples;   // Number of samples after trigger
 currentBsize = n_ai * n_s;        // Current size for buffer
 
 samplePhase = 0; // First phase: buffer prefill
 
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;  

 // Check if we only read one channel
 if ((n_ai==1)&&(stime<30e-6f))
    {
    // Perform a dummy read
    ain1.read_u16();     
    // Programs the ticker for one input optimized ISR version
    ticR.attach(&triggeredReadSingleISR,stime);   
    }
   else     
    { 
    // Programs the ticker for several inputs
    ticR.attach(&triggeredReadISR,stime);
    }
  
 // Wait till end
 while (!endTicker) { overrun = 0; PRO2_CLEAR }
 
 // Return data
 dumpTriggeredInBuffer();  // Dump data
 
 // Send CRC to end Tx
 sendCRC();
 }

/********************* STEP RESPONSE ***************************/

// Hardware profiling operation (if enabled)
//   Not implemented yet

// ISR for the stepResponse function
void stepResponseISR()
 {
 // Store analog data    
 storeAnalog();    
 
 // Increase sample
 samples++;
     
 // Check trigger position
 if (samples == triggerSample) aout1 = stepValue / MAX16F;
     
 // Check if we should end
 if (samples >= n_s)
    {
    // Disable ticker
    ticR.detach();     
    // Signal end
    endTicker = 1;    
    }        
    
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// ISR for the stepResponse function
// Time optimized version
// Only used for one channel and stime < 30us
void stepResponseSingleISR()
 {
 // Direct access to ADC registers 
 ADC1->CR |= ADC_CR_ADSTART;           
 while (!(ADC1->ISR & ADC_ISR_EOC));
 tranBuff[inBuffPos++]=(ADC1->DR)<<4;  
 
 if (inBuffPos == currentBsize) inBuffPos = 0;     
 
 // Increase sample
 samples++;
     
 // Check trigger position
 if (samples == triggerSample)
       DAC->DHR12R1 = (stepValue>>4);
     
 // Check if we should end
 if (samples >= n_s)
    {
    // Disable ticker
    ticR.detach();     
    // Signal end
    endTicker = 1;    
    }        
    
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// Implements command 'P'
// Step response
void stepResponse()
 {    
 // Read step value
 stepValue = getU16();
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK); // All Ok
 
 // Configure ticker ISR    
 samples = 0;               // Number of processed samples
 inBuffPos = 0;             // Current buffer position
 endTicker = 0;            // Ticker has not ended
 
 triggerSample = n_s/5;
 
 currentBsize = n_ai * n_s;        // Current size for buffer
     
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;    
     
 // Check if we only read one channel
 if ((n_ai==1)&&(stime<30e-6f))
    {
    // Perform a dummy read
    ain1.read_u16();    
    // Programs the ticker
    ticR.attach(&stepResponseSingleISR,stime);
    }
    else
    {     
    // Programs the ticker
    ticR.attach(&stepResponseISR,stime);
    }
 
 // Wait till end
 while (!endTicker) overrun = 0;
 
 // Return data
 dumpInBuffer();  // Dump data
 
 // Send CRC to end Tx
 sendCRC();
 }

/********************* WAVETABLE CODE ***************************/ 

// Load a wavetable
void loadWaveTable()
 {
 int i;    
     
 // Eliminate secondary wavetable
 w_s2 = 0;    
     
 // Get size
 w_s = getU16();
 
 // Check size
 if (w_s > BSIZE) 
    {
    w_s = 0; // Eliminate table
    
    // Calculate new memory configuration
    wave2buff=&buff[w_s];
    tranBuff =&buff[w_s];
 
    sendByte(NACK);
    sendCRC();
    return;    
    }
     
 // Calculate new memory configuration
 wave2buff=&buff[w_s];
 tranBuff =&buff[w_s];
 
 if (w_s > 0) 
   {
   // Load samples
   for(i=0;i<w_s;i++)
      buff[i] = getU16();
   }   

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);
    
 sendCRC();   
 }
 
// Load a secondary wavetable
void loadSecondaryWaveTable()
 {
 int i;    
     
 // Get size
 w_s2 = getU16();
 
 // Check size and primary wavetable
 if (w_s2 > wave2buffSize()) 
    {
    w_s2 = 0;
    // Calculate new memory configuration
    tranBuff =&buff[w_s+w_s2];
    
    sendByte(NACK);
    sendCRC();
    return;    
    }
 
 // Calculate new memory configuration
 tranBuff =&buff[w_s+w_s2];
 
 for(i=0;i<w_s2;i++)
    wave2buff[i] = getU16();

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);
    
 sendCRC();   
 }
 

/****************** WAVE RESPONSE CODE *************************/ 

// Hardware profiling operation (if enabled)
//    Not implemented

// ISR for the waveResponse function
void waveResponseISR()
 {
 // Write DAC
 aout1 = buff[w_pos++] / MAX16F;    
     
 // Store analog data    
 if (!w_n)
      {
      storeAnalog();    
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s) w_pos = 0;        
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      }                     
                 
 // Check wave rollover
 // if (w_pos == w_s) w_pos = 0;
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// ISR for the waveResponse function
// Time optimized version
// Only used for single ADC and stime < 30us
void waveResponseSingleISR()
 {
 // Write DAC
 DAC->DHR12R1 = (buff[w_pos++]>>4);
     
 // Store analog data    
 if (!w_n)
      {
      // Direct access to ADC registers 
      ADC1->CR |= ADC_CR_ADSTART;           
      while (!(ADC1->ISR & ADC_ISR_EOC));
      tranBuff[inBuffPos++]=(ADC1->DR)<<4;  
 
      if (inBuffPos == currentBsize) inBuffPos = 0;    
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s) w_pos = 0;        
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      }                     
                 
 // Check wave rollover
 // if (w_pos == w_s) w_pos = 0;
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// Wave response
void waveResponse()
 {
 // Read number of waves before mesurement    
 w_n = getU16();   

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);

 // Configure ticker ISR    
 samples = 0;               // Number of processed samples
 inBuffPos = 0;             // Current buffer position
 endTicker = 0;             // Ticker has not ended
 w_pos = 0;                 // Current wave position 

 currentBsize = n_ai * n_s;        // Current size for buffer
 
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;
 
 // Check if we only read one channel
 if ((n_ai==1)&&(stime<30e-6f))
    {
    // Perform a dummy read
    ain1.read_u16();    
    // Programs the ticker
    ticR.attach(&waveResponseSingleISR,stime);
    }
    else
    {    
    // Programs the ticker
    ticR.attach(&waveResponseISR,stime);
    }
   
 // Wait till end
 while (!endTicker) overrun = 0;
 
 // Return data
 dumpInBuffer();  // Dump data  
 
 // End sending CRC
 sendCRC(); 
 }    

/*************** DUAL WAVE RESPONSE CODE *************************/ 

// ISR for the dualWaveResponse function
void dualWaveResponseISR()
 {
 // Write DACs
 aout1 = buff[w_pos++] / MAX16F;    
 aout2 = wave2buff[w_pos2++] / MAX16F;
      
 // Store analog data    
 if (!w_n)
      {
      storeAnalog();    
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s)   w_pos = 0;
      if (w_pos2 == w_s2) w_pos2 = 0;
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      if (w_pos2 == w_s2) w_pos2 = 0;      
      }                     
                 
 // Check wave rollover
 //if (w_pos == w_s) w_pos = 0;
           
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }  
 
// ISR for the dualWaveResponse function
// Time optimized version
// Use only for single ADC read and stime < 35us
void dualWaveResponseSingleISR()
 {
 // Write DACs
 DAC->DHR12R1 = (buff[w_pos++]>>4);
 DAC->DHR12R2 = (wave2buff[w_pos2++]>>4);
     
 // Store analog data    
 if (!w_n)
      {
      // Direct access to ADC registers 
      ADC1->CR |= ADC_CR_ADSTART;           
      while (!(ADC1->ISR & ADC_ISR_EOC));
      tranBuff[inBuffPos++]=(ADC1->DR)<<4;  
 
      if (inBuffPos == currentBsize) inBuffPos = 0;     
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s)   w_pos = 0;
      if (w_pos2 == w_s2) w_pos2 = 0;
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      if (w_pos2 == w_s2) w_pos2 = 0;      
      }                     
                 
 // Check wave rollover
 //if (w_pos == w_s) w_pos = 0;
           
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }     

// Dual wave response
void dualWaveResponse()
 {
 // Read number of primary waves before mesurement    
 w_n = getU16();   

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);

 // Configure ticker ISR    
 samples = 0;               // Number of processed samples
 inBuffPos = 0;             // Current buffer position
 endTicker = 0;             // Ticker has not ended
 w_pos = 0;                 // Current wave position 
 w_pos2 = 0;                // Secondary wave position

 currentBsize = n_ai * n_s;        // Current size for buffer
 
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;    
 
 // Check if we only read one channel
 if ((n_ai==1)&&(stime<35e-6f))
    {
    // Perform a dummy read
    ain1.read_u16();   
    // Programs the ticker
    ticR.attach(&dualWaveResponseSingleISR,stime); 
    }
    else
    {
    // Programs the ticker
    ticR.attach(&dualWaveResponseISR,stime);
    }
   
 // Wait till end
 while (!endTicker) overrun = 0;
 
 // Return data
 dumpInBuffer();  // Dump data  
 
 // End sending CRC
 sendCRC(); 
 }    

/*************** SINGLE WAVE RESPONSE CODE **********************/ 
// Hardware profiling operation (if enabled)
//   PRO1 line high during ISR
//   PRO2 line mimics overrun variable 

// ISR for the singleWaveResponse function
void singleWaveResponseISR()
 {
 int a1;    
     
 PRO1_SET    
    
 // Write DAC1
 aout1 = buff[w_pos++] / MAX16F;   
     
 // Store analog data    
 if (!w_n)
      {
      // Store data  
      // Store data  
      a1 = ain_tran->read_u16();    
      tranBuff[inBuffPos++]=a1;    
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s) w_pos = 0;        
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      }                     
                 
 // Check wave rollover
 if (w_pos == w_s) w_pos = 0;
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;  
 
 PRO2_SET
 PRO1_CLEAR
 }   

// ISR for the singleWaveResponse function
// Time optimized version
// Only used for stime < 30us
void singleWaveResponseFastISR()
 {
 int a1;    
     
 PRO1_SET    
    
 // Write DAC1
 DAC->DHR12R1 = (buff[w_pos++]>>4);  /* New faster code */
     
 // Store analog data    
 if (!w_n)
      {
      // Store data  
      // Direct access to registers
      ADC1->CR |= ADC_CR_ADSTART;           
      while (!(ADC1->ISR & ADC_ISR_EOC));
      a1 = ADC1->DR;
      tranBuff[inBuffPos++]=a1<<4;    
     
      // Increase sample
      samples++;
     
      // Check if we should end
      if (samples >= n_s)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;    
           } 
      
      // Check wave rollover
      if (w_pos == w_s) w_pos = 0;        
      }
     else
      {
      // Check wave rollover    
      if (w_pos == w_s)
            {
            w_pos = 0;    
            w_n--;
            }
      }                     
                 
 // Check wave rollover
 if (w_pos == w_s) w_pos = 0;
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;  
 
 PRO2_SET
 PRO1_CLEAR
 }  

// Select analog channel
// In case of error, closes the communication and returns 0
// If all is ok, returns 1
int selectTranChannel(int channel)
 {
 if ((channel<0) || (channel>4))
          {
          sendByte(NACK);
          sendCRC();
          return 0;
          } 
          
 switch(channel)         
    {
    case 1:
        ain_tran=&ain1;
        break;
    case 2:
        ain_tran=&ain2;
        break;
    case 3:
        ain_tran=&ain3;
        break;
    case 4:
        ain_tran=&ain4;
        break;                        
    }
    
 return 1;   
 }    

// Single Wave response
void singleWaveResponse()
 {
 int channel;  
 
 PRO1_CLEAR // Reset profile lines
 PRO2_CLEAR  
     
 // Read channel to read    
 channel = getByte();   
          
 // Read number of waves before mesurement    
 w_n = getU16();   

 // Check of CRC
 if (!crcResponse()) return; 
 
 // Configure the input channel
 if (!selectTranChannel(channel)) return;
 
 // Dummy read
 ain_tran->read_u16();

 // Send ACK
 sendByte(ACK);

 // Configure ticker ISR    
 samples = 0;               // Number of processed samples
 inBuffPos = 0;             // Current buffer position
 endTicker = 0;             // Ticker has not ended
 w_pos = 0;                 // Current wave position 

 currentBsize = n_s;        // Current size for buffer
 
 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;    
 
 if (stime < 30e-6f)
     {
     // Programs the ticker with fast version
     ticR.attach(&singleWaveResponseFastISR,stime);
     }
     else
     {    
     // Programs the ticker with normal version
     ticR.attach(&singleWaveResponseISR,stime);
     }
   
 // Wait till end
 while (!endTicker) { overrun = 0; PRO2_CLEAR }
 
 // Return data
 dumpInSingleBuffer();  // Dump data  
 
 // End sending CRC
 sendCRC(); 
 }    

/****************** WAVE PLAY CODE *************************/ 

// ISR for the wavePlay function
void wavePlayISR()
 {
 // Write DAC (Old code)
 // aout1 = buff[w_pos++] / MAX16F;    
 
  // Write DACs (New faster code)
 DAC->DHR12R1 = (buff[w_pos++]>>4);
              
 // Check wave rollover    
 if (w_pos == w_s)
     {
     w_pos = 0;    
     w_n--;
     if (w_n <= 0)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;     
           return;
           }
     }
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// Wave Play
void wavePlay()
 {
 PRO1_SET
 // Read number of waves to send    
 w_n = getU16();   

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);

 // Configure ticker ISR    
 endTicker = 0;             // Ticker has not ended
 w_pos = 0;                 // Current wave position 

 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;    
 
 // Programs the ticker
 ticR.attach(&wavePlayISR,stime);
   
 // Wait till end
 while (!endTicker) overrun = 0;
 
 PRO1_CLEAR
 
 // Response code
 if (overrun_error)
        sendByte(TRAN_OVERRUN);
        else
        sendByte(TRAN_OK);  
 
 // End sending CRC
 sendCRC(); 
 }    

/****************** DUAL WAVE PLAY CODE *************************/ 

// ISR for the dualWavePlay function
void dualWavePlayISR()
 {
 // Write DAC (Old code)
 //aout1 = buff[w_pos++] / MAX16F; 
 //aout2 = wave2buff[w_pos2++] / MAX16F; 
 
 // Write DACs (New faster code)
 DAC->DHR12R1 = (buff[w_pos++]>>4);
 DAC->DHR12R2 = (wave2buff[w_pos2++]>>4);
              
 // Check primary wave rollover    
 if (w_pos == w_s)
     {
     w_pos = 0;    
     w_n--;
     if (w_n <= 0)
           {
           // Disable ticker
           ticR.detach();     
           // Signal end
           endTicker = 1;     
           }
     }
     
 // Check for secondary wave rollover
 if (w_pos2 == w_s2) w_pos2 = 0;   
        
 // Check for overrun
 if (overrun)
    overrun_error = 1;
    
 overrun = 1;   
 }    

// Dual Wave Play
void dualWavePlay()
 {
 // Read number of primary waves to send    
 w_n = getU16();   

 // Check of CRC
 if (!crcResponse()) return; 
 
 sendByte(ACK);

 // Configure ticker ISR    
 endTicker = 0;             // Ticker has not ended
 w_pos =  0;                // Current primary wave position 
 w_pos2 = 0;                // Current secondary wave position

 // Clear overrun variables
 overrun_error = 0;
 overrun = 0;    
 
 // Programs the ticker
 ticR.attach(&dualWavePlayISR,stime);
   
 // Wait till end
 while (!endTicker) overrun = 0;
 
 // Response code
 if (overrun_error)
        sendByte(TRAN_OVERRUN);
        else
        sendByte(TRAN_OK);  
 
 // End sending CRC
 sendCRC(); 
 }    

/***************** DC DIGITAL IO *********************************/

// Digital IO mode
void dioMode()
 {
 int line,mode,error; 
  
 // Read line to configure 
 line = getByte(); 
     
 // Read mode to set
 mode = getByte();
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 // No error for now
 error = 0;
 
 // Check line number
 if ((line <= 0)||(line > NDIO)) error = 1;
 
 // Set dio mode
 if (!error)
    switch(mode)
        {
        case 10: 
           dioList[line-1]->input();
           dioList[line-1]->mode(PullNone);
           break;
        case 11: 
           dioList[line-1]->input();        
           dioList[line-1]->mode(PullUp);
           break;  
        case 12: 
           dioList[line-1]->input();
           dioList[line-1]->mode(PullDown);
           break;                        
        case 20: 
           dioList[line-1]->mode(PullNone);        
           dioList[line-1]->output();        
           break;  
//        case 21: 
//           dioList[line-1]->mode(OpenDrain);        
//           dioList[line-1]->output();        
//           break; 
        default:
           error = 1;
           break;                             
        }
        
 if (error)
    sendByte(NACK);
    else
    sendByte(ACK);     
 
 // End sending CRC
 sendCRC(); 
 }
 
// Digital Write
void dioWrite()
 {
 int line,value; 
  
 // Read line to write 
 line = getByte(); 
     
 // Value to set
 value = getByte();
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 // Check line number
 if ((line <= 0)||(line > NDIO)) 
     {
     sendByte(NACK);
     sendCRC();
     return;
     }
 
 // Set dio value
 dioList[line-1]->write(value);

 // Send ACK and CRC
 sendByte(ACK);     
 sendCRC(); 
 } 
 
// Digital Read
void dioRead()
 {
 int line,value; 
  
 // Read line to read
 line = getByte(); 
 
 // Check of CRC
 if (!crcResponse()) return; 
 
 // Check line number
 if ((line <= 0)||(line > NDIO)) 
     {
     sendByte(NACK);
     sendCRC();
     return;
     }
 
 // Send ACK
 sendByte(ACK);
 
 // Read and send dio value
 value=dioList[line-1]->read();
 if (value)
    sendByte(1);
    else
    sendByte(0);
 
 // Send CRC     
 sendCRC(); 
 }  

/***************** MAIN LOOP CODE ********************************/

// Soft reset
// Put the system in default reset state
void softReset(void)
 {
 int i;    
     
 // Sample time period defaults to 1ms
 stime = 0.001;
 
 // Set number of DC readings to 10
 nread = 10;
 
 // Input configuration
 n_ai = 1;     // Number of analog inputs
 n_di = 0;     // Number of digital inputs (always zero)
 n_s  = 1000;  // Number of samples
 
 // Eliminate wavetables
 w_s =  0;  
 w_s2 = 0;
 
 // Initialize unified memory
 wave2buff = buff;
 tranBuff  = buff;  
 
 // Set DACs to zero
 aout1 = 0.0;
 aout2 = 0.0; 
 
 // Fill ain list
 ainList[0]=&ain1;
 ainList[1]=&ain2;
 ainList[2]=&ain3;
 ainList[3]=&ain4;
 
 // Configure DIO
 #ifdef EXIST_DIO
 // Setup dioList
 dioList[0]=&dio1;
 dioList[1]=&dio2;
 dioList[2]=&dio3;
 dioList[3]=&dio4;
 dioList[4]=&dio5;
 dioList[5]=&dio6;
 dioList[6]=&dio7;
 dioList[7]=&dio8;
 // Default configuration
 for(i=0;i<NDIO;i++)
    {
    dioList[i]->mode(PullNone);
    dioList[i]->input();    
    }    
 #endif
 }

// Process one character received from the PC
void process(int car)
 {
 int i;
 uint16_t value;
  
 // Initialize Tx CRC
 startTx();
    
 switch(car)
    {
    case 'F': // Get firmware string
        sendString(BSTRING);
        sendString(VSTRING);
        sendString("\n\r");
        break;
    case 'M': // Get magic
        // Check CRC of command. Returns 1 if Ok
        // On error Sends ECRC + CRC and return 0
        if (!crcResponse()) return;
        sendByte(ACK);
        // Send magic
        for(i=0;i<MAGIC_SIZE;i++)
            sendByte(magic[i]);
        // Send CRC
        sendCRC();
        break; 
    case 'I': // Get board capabilities
        // Check CRC of command. Returns 1 if Ok
        // On error Sends ECRC + CRC and return 0
        if (!crcResponse()) return;
        sendByte(ACK);
            
        sendByte(NDACS);                //  1
        sendByte(NADCS);                //  2
        sendU16(BSIZE);                 //  4 Buffer
        sendMantExp(MAX_S_M,MAX_S_E);   //  7
        sendMantExp(MIN_S_M,MIN_S_E);   // 10
        sendMantExp(VDD_M,VDD_E);       // 13
        sendMantExp(MAX_SF_M,MAX_SF_E); // 16
        sendMantExp(VREF_M,VREF_E);     // 29
        sendByte(DAC_BITS);             // 20
        sendByte(ADC_BITS);             // 21
        sendByte(NDIO);                 // 22
        sendByte(resetState);           // 23
        
        // Send CRC
        sendCRC();
        break;
    case 'L' : // Send pin list
        // Check CRC of command. Returns 1 if Ok
        // On error Sends ECRC + CRC and return 0
        if (!crcResponse()) return;
        sendByte(ACK);
        
        sendString(PIN_LIST);
        
        // Send CRC
        sendCRC();        
        break;
        
    
    case 'A' : // ADC Read
        i = getByte();   // Channel to read
        // Check CRC of command. Returns 1 if Ok
        // On error Sends ECRC + CRC and return 0
        if (!crcResponse()) return;   
             
        /*     
        switch(i)
            {
            case 1:
               value = ain1.read_u16();  // Two reads
               value = ain1.read_u16(); 
               break;  
            case 2:
               value = ain2.read_u16();  // Two reads
               value = ain2.read_u16(); 
               break; 
            case 3:
               value = ain3.read_u16();  // Two reads
               value = ain3.read_u16(); 
               break; 
            case 4:
               value = ain4.read_u16();  // Two reads
               value = ain4.read_u16(); 
               break;  
            default:
               sendByte(NACK);
               sendCRC();
               return;                                              
            }  
        */
        if ((i<1)||(i>NADCS))
            {
            sendByte(NACK);
            sendCRC();
            return;     
            }
            
        value = analogRead(i);    
               
        sendByte(ACK);    
        sendU16(value);
        sendCRC();
        break;        
    
    case 'D' : // DAC Write
        i = getByte();          // Channel to write
        value = getU16();       // Read value to set
        // Check CRC of command. Returns 1 if Ok
        // On error Sends ECRC + CRC and return 0
        if (!crcResponse()) return;          
        switch(i)
            {
            case 1: 
               aout1 = value / MAX16F;   // Scale to float and send
               break;
            case 2:
               aout2 = value / MAX16F;   // Scale to float and send
               break;
            #ifdef EXIST_DAC3   
            case 3:
               aout3 = value / MAX16F;   // Scale to float and send
               break;          
            #endif   
            default:
               sendByte(NACK);
               sendCRC();
               return;                
            }  
        sendByte(ACK);    
        sendCRC();     
        resetState=0;  // State change         
        break;    
                          
    case 'R': // Set sample period time
        setSampleTime();
        resetState=0;  // State change
        break;  
    case 'S': // Set Storage
        setStorage();
        resetState=0;  // State change
        break;      
    case 'Y': // Async Read
        asyncRead();
        break;
    case 'G': // Triggered Read
        triggeredRead();
        break;        
    case 'P': // Step response
        stepResponse();
        break;    
        
    case 'W': // Load wavetable
        loadWaveTable();
        resetState=0;  // State change
        break;  
    case 'w': // Load secondary wavetable
        loadSecondaryWaveTable();
        resetState=0;  // State change
        break;         
    case 'V': // Wave response
        waveResponse();
        break;  
    case 'v': // Dual wave response
        dualWaveResponse();
        break;          
    case 'X': // Single Wave response
        singleWaveResponse();
        break; 
    case 'Q': // Wave Play
        wavePlay();
        break;  
    case 'q': // Wave Play
        dualWavePlay();
        break;                 
        
    case 'E': // Soft Reset
        if (!crcResponse()) return;
        
        softReset();
        resetState=1;  // Return to reset state
    
        sendByte(ACK);    
        sendCRC();
        break;   
        
    case 'H': // DIO mode
        dioMode();
        resetState=0;  // State change
        break;  
    case 'J': // DIO Write
        dioWrite();
        resetState=0;  // State change
        break;    
    case 'K': // DIO Read
        dioRead();
        break;   
        
    case 'N': // Number of reads in DC
        value = getU16();             // Read value to set
        if (!crcResponse()) return;   // Check CRC
        if (value==0) value=1;        // At least it shall be one
        nread = value;
        sendByte(ACK);                // Send ACK and CRC
        sendCRC();    
        resetState=0;  // State change          
        break;                          
    
    default:
        // Unknown command
        sendByte(NACK);
        sendCRC();    
        break;             
    }     
 }    

int main() 
 {
 int car;
 
 // Generate soft reset
 softReset();
 
 pc.printf("%s%s\n\r",BSTRING,VSTRING);

 // Reset profile lines (if enabled)
 PRO1_CLEAR
 PRO2_CLEAR
 
 // New ADC code
 //adc_init();

 // Loop that processes each received char
 while(1) 
    {
    startRx();        // Init Rx CRC
    car = getByte();  // Get command
    process(car);     // Process command
    }
 }