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
Diff: main.cpp
- Revision:
- 0:39a545e08ccd
- Child:
- 1:d81bef65eece
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sat Feb 10 09:43:16 2018 +0000 @@ -0,0 +1,2244 @@ +/******************************************************* + + 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 + } + } + +