Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
DC590B_enhanced.ino
Go to the documentation of this file.
1 //! @todo Review this file? Document with Doxygen? Time permitting...
2 /*
3 DC590B USB to Serial Controller
4 
5 This file contains the routines to emulate the DC590B USB to Serial Converter. All commands
6 are supported except Uxxy the Write Port D bus. Added the 'D' delay ms command.
7 With this program, the Linduino can be used by the QuikEval program running on a PC
8 to communicate with QuikEval compatible demo boards.
9 
10 The Kxy bit bang command uses the following pin mappings :
11 0-Linduino 2
12 1-Linduino 3
13 2-Linduino 4
14 3-Linduino 5
15 4-Linduino 6
16 5-Linduino 7
17 
18 
19 Copyright 2018(c) Analog Devices, Inc.
20 
21 All rights reserved.
22 
23 Redistribution and use in source and binary forms, with or without
24 modification, are permitted provided that the following conditions are met:
25  - Redistributions of source code must retain the above copyright
26  notice, this list of conditions and the following disclaimer.
27  - Redistributions in binary form must reproduce the above copyright
28  notice, this list of conditions and the following disclaimer in
29  the documentation and/or other materials provided with the
30  distribution.
31  - Neither the name of Analog Devices, Inc. nor the names of its
32  contributors may be used to endorse or promote products derived
33  from this software without specific prior written permission.
34  - The use of this software may or may not infringe the patent rights
35  of one or more patent holders. This license does not release you
36  from the requirement that you obtain separate licenses from these
37  patent holders to use this software.
38  - Use of the software either in source or binary form, must be run
39  on or directly connected to an Analog Devices Inc. component.
40 
41 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
42 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
43 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
45 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
47 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
48 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51  */
52 
53 #include <Arduino.h>
54 #include <stdint.h>
55 #include "Linduino.h"
56 #include "QuikEval_EEPROM.h"
57 #include "LT_SPI.h"
58 #include "UserInterface.h"
59 #include "LT_I2C.h"
60 #include <Wire.h>
61 #include <SPI.h>
62 
63 // define a "spoof_board_id" to force the "i" command to return a specific ID string.
64 // This can be used to fake QuikEval into loading a specific GUI, even if the ID EEPROM
65 // is not present. A few examples are below. NOT defining will result in normal behavior,
66 // "i" command will cause EEPROM to be read.
67 
68 //#define spoof_board_id "LTC4261,Cls,D4261,01,01,DC,DC998A,--------------"
69 //#define spoof_board_id "LTC2440,Cls,D2440,01,01,DC,DC570,---------------"
70 //#define spoof_board_id "LTC2946,Cls,D2946,01,01,DC,DC2156A,-------------"
71 
72 // timeouts
73 #define READ_TIMEOUT 20
74 #define MISO_TIMEOUT 1000
75 
76 // recording mode constants
77 #define RECORDING_SIZE 50
78 const byte off = 0;
79 const byte playback = 1;
80 
81 // serial mode constants
82 const byte spi_mode = 0;
83 const byte i2c_mode = 1;
84 const byte i2c_auxiliary_mode = 2;
85 
86 // hex conversion constants
87 char hex_digits[16]=
88 {
89  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
90 };
91 
92 // spi clock divider
93 const char spi_divider = SPI_CLOCK_DIV32; // configure the spi port for 4MHz SCK (500kHz@div32??)
94 
95 // global variables
96 byte serial_mode = spi_mode; // current serial mode
97 byte recording_mode = off; // recording mode off
98 ////////////////////////////////////////////////////
99 // CHANGED MAJOR VERSION to 2 FOR ENHANCED VERSION//
100 ////////////////////////////////////////////////////
101 char id_string[51]="USBSPI,PIC,02,01,DC,DC590,----------------------\n\0"; // id string
103 {
104  '0', 'x', '0', '0', '\0'
105 }; // buffer for ASCII hex to byte conversion
107 {
108  '\0','\0','\0'
109 }; // buffer for byte to ASCII hex conversion
111 {
112  '\0'
113 }; // buffer for saving recording loop
114 byte recording_index = 0; // index to the recording buffer
115 
116 char get_char();
117 
118 void byte_to_hex(byte value)
119 // convert a byte to two hex characters
120 {
121  byte_to_hex_buffer[0]=hex_digits[value>>4]; // get upper nibble
122  byte_to_hex_buffer[1]=hex_digits[(value & 0x0F)]; // get lower nibble
123  byte_to_hex_buffer[2]='\0'; // add NULL at end
124 }
125 
126 byte read_hex()
127 // read 2 hex characters from the serial buffer and convert
128 // them to a byte
129 {
130  byte data;
133  data = strtol(hex_to_byte_buffer, NULL, 0);
134  return(data);
135 }
136 
137 char get_char()
138 // get the next character either from the serial port
139 // or the recording buffer
140 {
141  char command='\0';
142  if (recording_mode != playback)
143  {
144  // read a command from the serial port
145  while (Serial.available() <= 0);
146  return(Serial.read());
147  }
148  else
149  {
150  // read a command from the recording buffer
152  {
153  command = recording_buffer[recording_index++];
154  // disregard loop commands during playback
155  if (command == 'w') command='\1';
156  if (command == 't') command='\1';
157  if (command == 'v') command='\1';
158  if (command == 'u') command='\1';
159  }
160  else
161  command = '\0';
162  if (command == '\0')
163  {
164  recording_index = 0;
166  }
167  return(command);
168  }
169 }
170 int i = 0;
171 unsigned char pseudo_reset = 0;
172 
173 void setup()
174 // Setup the program
175 {
176  digitalWrite(QUIKEVAL_GPIO, LOW);
177  digitalWrite(QUIKEVAL_CS, HIGH);
178  digitalWrite(2, LOW);
179  digitalWrite(3, LOW);
180  digitalWrite(4, LOW);
181  digitalWrite(5, LOW);
182  digitalWrite(6, LOW);
183  digitalWrite(7, LOW);
184  pinMode(QUIKEVAL_GPIO, OUTPUT);
185  pinMode(QUIKEVAL_CS, OUTPUT);
186  pinMode(2, OUTPUT);
187  pinMode(3, OUTPUT);
188  pinMode(4, OUTPUT);
189  pinMode(5, OUTPUT);
190  pinMode(6, OUTPUT);
191  pinMode(7, OUTPUT);
192 
193  Serial.begin(115200); // enable the serial port for 115200 baud
194 
196  quikeval_SPI_connect(); // Connect SPI to main data port
197 
198  quikeval_I2C_init(); // Configure the EEPROM I2C port for 100kHz SCK
199  Serial.print("hello\n");
200  Serial.flush();
201 }
202 
203 void loop()
204 {
205  byte tx_data;
206  byte rx_data;
207  byte pin_value;
208  int delay_value;
209  int pin;
210  char command;
211  int byte_count;
212  long delay_count;
213  command = get_char();
214  switch (command)
215  {
216  case 'D':
217  // delay milliseconds
218  delay_value = read_hex();
219  delay_value<<=8;
220  delay_value|=read_hex();
221  delay(delay_value);
222  break;
223  case 'g':
224  // IO pin low
226  break;
227  case 'G':
228  // IO pin high
230  break;
231  case 'H': // wait for MISO to go high with a timeout
232  delay_count = 0;
233  while (1)
234  {
235  if (input(MISO)==1) break; // MISO is high so quit
236  if (delay_count++>MISO_TIMEOUT)
237  {
238  //Serial.print('T'); // timeout occurred. Print 'T'
239  break;
240  }
241  else delay(1);
242  }
243  break;
244  case 'i':
245  // send controller id string
246  pseudo_reset = 0;
247  Serial.print(id_string);
248  Serial.print('\0');
249  Serial.flush();
250  break;
251  case 'I':
252 #ifdef spoof_board_id
253  Serial.print(spoof_board_id);
254  Serial.print('\0');
255  Serial.print('\0');
256 #else
257  // get controller id string
258  quikeval_SPI_connect(); // Connect SPI to main data port
259  pseudo_reset = 0;
260  byte_count = read_quikeval_id_string(&ui_buffer[0]);
261  if (byte_count!=0)
262  {
263  Serial.print(ui_buffer);
264  Serial.print("\n\0");
265  Serial.flush();
266  }
267 #endif
268  break;
269  case 'K':
270  // Bang pin. The pin assignments are :
271  // 0: PIND2, Arduino 2
272  // 1: PIND3, Arduino 3
273  // 2: PIND4, Arduino 4
274  // 3: PIND5, Arduino 5
275  // 4: PIND6, Arduino 6
276  // 5: PIND6, Arduino 7
277 
278  pin_value = get_char(); // read the value
279 // pin = get_char()-0x30; // read the pin
280  pin = get_char(); // read the pin
281 // if (pin_value == '0') digitalWrite(pin+2, LOW);
282 // else digitalWrite(pin+2, HIGH);
283 
284  digitalWrite(pin-0x30+2, pin_value == '0' ? LOW : HIGH);
285  break;
286  case 'k':
287  // Get pin state. The digial pin assignments are the same as for 'K',
288  // Analog pin mappings as follows:
289  // 6: Analog A0 (read only)
290  // 7: Analog A1 (read only)
291  // 8: Analog A2 (read only)
292  // 9: Analog A3 (read only)
293  pin = get_char(); // read the pin
294  if (pin <= '5')
295  {
296  Serial.print(digitalRead(pin-0x30+2));
297  }
298  else if (pin == 'C') // To read MISO pin
299  {
300  int val;
301  //pin = read_hex();
302  val = digitalRead(12);
303  byte_to_hex(val);
304  Serial.print(byte_to_hex_buffer);
305  }
306  else
307  {
308  int val = analogRead(pin - '6');
309  if (val < 10)
310  {
311  Serial.print("000");
312  }
313  else if (val < 100)
314  {
315  Serial.print("00");
316  }
317  else if (val < 1000)
318  {
319  Serial.print("0");
320  }
321  Serial.print(val);
322  break;
323  }
324  break;
325  case 'j':
326  // Set pin mode. The pin assignments are the same as for 'K':
327  pin_value = get_char(); // read the value
328  pin = get_char(); // read the pin
329  pinMode(pin-0x30+2, pin_value == '0' ? INPUT : OUTPUT);
330  break;
331  case 'L':
332  // wait for MISO to go low with a timeout
333  delay_count = 0;
334  while (1)
335  {
336  if (input(MISO)==0) break; // MISO is low so quit
337  if (delay_count++>MISO_TIMEOUT)
338  {
339  //Serial.print('T'); // timeout occurred. Print 'T'
340  break;
341  }
342  else delay(1);
343  }
344  break;
345  case 'M':
346  // change the serial mode
347  command = get_char();
348  switch (command)
349  {
350  case 'I':
351  // I2C mode
353  // enable_main_I2C();
355  break;
356  case 'S':
357  // spi mode
359  // Need to send command to disable LTC4302
360  // enable_main_SPI();
362  break;
363  case 'X': // axillary I2C mode - no hardware action necessary, always available.
366  break;
367  case '0': // New for Enhanced version - set SPI mode on the fly. (Mainly for Altera SPI-Avalon MM bridge)
368  SPI.setDataMode(SPI_MODE0);
369  break;
370  case '1':
371  SPI.setDataMode(SPI_MODE1);
372  break;
373  case '2':
374  SPI.setDataMode(SPI_MODE2);
375  break;
376  case '3':
377  SPI.setDataMode(SPI_MODE3);
378  break;
379  case 'a':
380  SPI.setClockDivider(SPI_CLOCK_DIV2);
381  break;
382  case 'b':
383  SPI.setClockDivider(SPI_CLOCK_DIV4);
384  break;
385  case 'c':
386  SPI.setClockDivider(SPI_CLOCK_DIV8);
387  break;
388  case 'd':
389  SPI.setClockDivider(SPI_CLOCK_DIV16);
390  break;
391  case 'e':
392  SPI.setClockDivider(SPI_CLOCK_DIV32);
393  break;
394  case 'f':
395  SPI.setClockDivider(SPI_CLOCK_DIV64);
396  break;
397  case 'g':
398  SPI.setClockDivider(SPI_CLOCK_DIV128);
399  break;
400  }
401  //delay(1);
402  break;
403  case 'p':
404  // I2C stop
405  // Switching BACK to the i2c_stop() function call. See Rev 1405, LT_i2c.cpp, Linduino One branch
406  if (serial_mode!=spi_mode) i2c_stop(); // TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // I2C stop //i2c_stop();
407  // if(serial_mode == i2c_auxiliary_mode) i2c_stop();
408  break;
409  case 'P':
410  // ping
411  Serial.print('P');
412  delay(5);
413  break;
414  case 'Q':
415  // Read byte in I2C mode only. Add ACK
416  switch (serial_mode)
417  {
418  case i2c_mode:
419  rx_data = i2c_read(WITH_ACK);
420  byte_to_hex(rx_data);
421  Serial.print(byte_to_hex_buffer);
422  break;
423  case i2c_auxiliary_mode:
424  rx_data = i2c_read(WITH_ACK);
425  byte_to_hex(rx_data);
426  Serial.print(byte_to_hex_buffer);
427  break;
428  }
429  break;
430 
431  case 'r':
432  rx_data = spi_read(0);
433  byte_to_hex(rx_data);
434  Serial.print(byte_to_hex_buffer);
435  break;
436 
437  case 'R':
438  // Read byte, add NACK in I2C mode
439  switch (serial_mode)
440  {
441  case spi_mode:
442  rx_data = spi_read(0);
443  byte_to_hex(rx_data);
444  Serial.print(byte_to_hex_buffer);
445  break;
446  case i2c_mode:
447  rx_data = i2c_read(WITH_NACK);
448  byte_to_hex(rx_data);
449  Serial.print(byte_to_hex_buffer);
450  break;
451  case i2c_auxiliary_mode:
452  rx_data = i2c_read(WITH_NACK);
453  byte_to_hex(rx_data);
454  Serial.print(byte_to_hex_buffer);
455  break;
456  }
457  break;
458  case 's': // I2C start
459  if (serial_mode == i2c_mode) i2c_start();
461  break;
462  case 'S': // send byte
463  tx_data = read_hex();
464  switch (serial_mode)
465  {
466  case spi_mode:
467  spi_write(tx_data);
468  break;
469  case i2c_mode:
470  if (i2c_write(tx_data)==1) Serial.print('N');
471  break;
472  case i2c_auxiliary_mode:
473  if (i2c_write(tx_data)==1) Serial.print('N');
474  break;
475  }
476  break;
477  case 't': // recording loop
478  recording_index = 0;
479  do
480  {
481  command = get_char();
482  if (command == 'u') // stop recording
483  {
485  recording_index = 0;
486  break;
487  }
488  else // add character to recording buffer
489  {
491  }
492  }
493  while (1);
494  break;
495  case 'T': // transceive byte
496  tx_data = read_hex();
497  if (serial_mode == spi_mode)
498  {
499  rx_data = spi_read(tx_data);
500  byte_to_hex(rx_data);
501  Serial.print(byte_to_hex_buffer);
502  }
503  break;
504  case 'v': // echo recording loop
505  Serial.print(recording_buffer);
506  break;
507  case 'w':
509  break;
510  case 'x':
512  break;
513  case 'X':
515  break;
516  case 'Z': // line feed
517  Serial.print('\n');
518  Serial.flush();
519  break;
520  case 0x80: // Reset
521  if (pseudo_reset == 0)
522  {
523  delay(500); // The delay is needed for older GUI's
524  Serial.print("hello\n");
525  pseudo_reset = 1;
526  }
527  break;
528  }
529 }
char recording_buffer[RECORDING_SIZE]
char id_string[51]
const byte i2c_auxiliary_mode
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
static void byte_to_hex(byte value)
static int i
Header File for Linduino Libraries and Demo Code.
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
byte serial_mode
const byte playback
void i2c_stop()
Write stop bit to the hardware I2C port.
Definition: LT_I2C.cpp:462
int8_t i2c_start()
Write start bit to the hardware I2C port.
Definition: LT_I2C.cpp:425
char byte_to_hex_buffer[3]
byte recording_index
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
#define WITH_NACK
Use with i2c_read(WITH_NACK) to read without an acknowledge.
Definition: LT_I2C.h:91
unsigned char pseudo_reset
const byte i2c_mode
static void setup()
#define QUIKEVAL_GPIO
Linduino QuikEval GPIO pin (QuikEval connector pin 14) connects to Arduino pin 9. ...
Definition: Linduino.h:56
byte read_hex()
int8_t i2c_write(uint8_t data)
Send a data byte to hardware I2C port.
Definition: LT_I2C.cpp:470
char hex_digits[16]
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
QuikEval EEPROM Library.
#define input(pin)
Return the state of pin "pin".
Definition: Linduino.h:79
void quikeval_SPI_init(void)
Configure the SPI port for 4Mhz SCK.
Definition: LT_SPI.cpp:151
const byte spi_mode
char get_char()
const char spi_divider
static void loop()
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
char hex_to_byte_buffer[5]
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
#define MISO_TIMEOUT
#define RECORDING_SIZE
uint8_t i2c_read(int8_t ack)
Read a data byte from the hardware I2C port.
Definition: LT_I2C.cpp:491
const byte off
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
void quikeval_I2C_connect(void)
Switch MUX to connect I2C pins to QuikEval connector.
Definition: LT_I2C.cpp:401
#define WITH_ACK
Use with i2c_read(WITH_ACK) to read with an acknowledge.
Definition: LT_I2C.h:90
#define QUIKEVAL_CS
QuikEval CS pin (SPI chip select on QuikEval connector pin 6) connects to Arduino SS pin...
Definition: Linduino.h:57
uint8_t read_quikeval_id_string(char *buffer)
Read the id string from the EEPROM, then parse the product name, demo board name, and demo board opti...
char ui_buffer[UI_BUFFER_SIZE]
byte recording_mode