Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
DC590_subset.ino
Go to the documentation of this file.
1 
2 /*!
3 
4 @verbatim
5 
6 
7 tinyDC590 is used to give basic DC590B compatibility to e.g. DC2574A_KIT sketch so
8 it can also be operated together with the LTC2947 GUI
9 
10 DC590B compatibility:
11 tinyDC590 provides a subset of the DC590B commands.
12 This way the e.g. the LTC2947 GUI is also able to communicate with the DC2574A_KIT sketch which enables the
13 user to use the GUI to change LTC2947 configuration e.g. to set alarm thresholds etc.
14 The main limitations of this compatibility mode are:
15 - EEPROM read from the DC2334A demo board is faked (it will always report the right EEPROM string)
16 - SPI operation is not supported, due to incompatibility with the optional LCD Keypad Shield
17 
18 Command Function Notes
19 Q Receive Byte * I2C only, send ACK
20 R Receive Byte * I2C only, sends NACK
21 Sxx Send byte (2 hex chars) * SPI and I2C. Returns ‘N’ if slave NACKs.
22 s Send start condition I2C only
23 p Send stop condition I2C only
24 Z Send line feed to host (0x0A)
25 I Read demo board info.
26 i Read contoller ID and firmware rev
27 O Turn isolated power on
28 o Turn isolated power off
29 MI Switch to isolated I2C mode
30 Kxy Bang pin, x argument is ‘0’ or ‘1’ for low or high, y is pin address, see below.
31 jxy Set pin mode, x argument is ‘0’ or ‘1’ for INPUT or OUTPUT, y is pin address, see below.
32 ky Read pin, answer is ‘0’ or ‘1’ for low or high, y is pin address, see below.
33 Uxxy Write Port D bus, xx is ASCII Hex data, y is strobe pin address, strobed low.
34 D Delay milliseconds
35 P PingPause (echo P, wait 5 ms)
36 g IO pin low
37 G IO pin high
38 H Wait for SDO=1 (SPI only) ‘T’ on timeout
39 L Wait for SDO=0 (SPI only) ‘T’ on timeout
40 0x80 DC590B pseudo Reset
41 
42 
43 the following DC590B commands are NOT implemented:
44 r Receive 7 bits In SPI mode only.
45 t Begin recording loop
46 u Stop recording loop
47 v Echo loop
48 Txx Tranceive (send and receive) * (SPI only)
49 w Loop until another command rec’d
50 X CS=1
51 x CS=0
52 MS Switch to isolated SPI mode
53 MX Switch to auxillary I2C mode
54 
55 @endverbatim
56 
57 
58 
59 Copyright 2018(c) Analog Devices, Inc.
60 
61 All rights reserved.
62 
63 Redistribution and use in source and binary forms, with or without
64 modification, are permitted provided that the following conditions are met:
65  - Redistributions of source code must retain the above copyright
66  notice, this list of conditions and the following disclaimer.
67  - Redistributions in binary form must reproduce the above copyright
68  notice, this list of conditions and the following disclaimer in
69  the documentation and/or other materials provided with the
70  distribution.
71  - Neither the name of Analog Devices, Inc. nor the names of its
72  contributors may be used to endorse or promote products derived
73  from this software without specific prior written permission.
74  - The use of this software may or may not infringe the patent rights
75  of one or more patent holders. This license does not release you
76  from the requirement that you obtain separate licenses from these
77  patent holders to use this software.
78  - Use of the software either in source or binary form, must be run
79  on or directly connected to an Analog Devices Inc. component.
80 
81 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
82 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
83 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
84 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
85 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
86 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
87 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
88 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
89 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
90 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91 */
92 
93 #include <SPI.h>
94 #include <LT_SPI.h>
95 #include <LT_I2C.h>
96 #include <Linduino.h>
97 #include "arduino.h"
98 
99 // for quikeval compatibility only
100 #define MISO_TIMEOUT 1000
101 
102 unsigned char pseudo_reset = 0;
103 // serial mode constants
104 const byte spi_mode = 0;
105 const byte i2c_mode = 1;
106 const byte i2c_auxiliary_mode = 2;
107 byte serial_mode = spi_mode; // current serial mode
108 
109 /** \brief DC590 busy flag. Asserted while DC590B command is processed */
110 boolean dc590Busy = false;
111 
112 /** \brief hex conversion constants */
113 char hex_digits[16] =
114 {
115  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
116 };
117 
118 /** \brief buffer for ASCII hex to byte conversion */
120 {
121  '0', 'x', '0', '0', '\0'
122 };
123 
124 
125 /** \brief buffer for byte to ASCII hex conversion */
127 {
128  '\0', '\0', '\0'
129 };
130 
131 
132 
133 // Queue structure to store/buffer characters received from serial port:
134 // only necessary to buffer data from the serial interface if DC590B compatibility mode is used
135 
136 /** \brief max elements in the queue*/
137 #define QUEUE_ELEMENTS 250
138 
139 /** \brief queue size. */
140 #define QUEUE_SIZE (QUEUE_ELEMENTS + 1)
141 
142 /** \brief The queue */
143 uint8_t Queue[QUEUE_SIZE];
144 
145 /** \brief The queue in element. */
146 uint8_t QueueIn = 0;
147 
148 /** \brief The queue out element */
149 uint8_t QueueOut = 0;
150 
151 /** \fn void EnqueueSerialData()
152 \brief Enqueue serial data. */
154 {
155  uint8_t help, help2;
156  do
157  {
158  help = Serial.available(); // max 64 bytes!
159  }
160  while ((help == 0) && (QueueIn == QueueOut)); // no new data and queue is empty
161 
162  // helper is needed to check if queue is full
163  help2 = ((QueueOut + QUEUE_ELEMENTS) % QUEUE_SIZE);
164 
165  while (
166  (help != 0) && // data available
167  (QueueIn != help2) // queue not full
168  )
169  {
170  // store byte to queue
171  Queue[QueueIn] = Serial.read();
172  QueueIn = (QueueIn + 1) % QUEUE_SIZE;
173  help = Serial.available(); // update number of remaining bytes
174  }
175 }
176 
177 /** \fn char DequeueChar()
178 \brief Dequeue character.
179 \return A char. */
181 {
182  // dequeue oldest byte from queue
183  uint8_t help = Queue[QueueOut];
184  QueueOut = (QueueOut + 1) % QUEUE_SIZE;
185  return help;
186 }
187 
188 /** \fn char get_char()
189 \brief Gets the character. get the next character either from the serial port or the internal queue
190 \return The character. */
191 char get_char()
192 {
194  return DequeueChar();
195 }
196 
197 /** \fn boolean CheckSerialData()
198 \brief Determines if serial data is available and stores data in the queue
199 \return true if new data is available */
201 {
202  if (Serial.available())
204 
205  return QueueIn != QueueOut;
206 }
207 
208 /** \fn boolean DelayAndCheckSerialData(unsigned long ms)
209 \brief Delay and check serial data. (while delaying we periodically check for new serial data and store the data)
210 \param ms delay in milliseconds.
211 \return true if new serial data is available */
212 boolean DelayAndCheckSerialData(unsigned long ms)
213 {
214  ms += millis();
215  do
216  {
217  if (Serial.available())
219  }
220  while (millis() < ms);
221 
222  return QueueIn != QueueOut;
223 }
224 
225 /** \fn void byte_to_hex(byte value)
226 \brief convert a Byte to two hexadecimal characters. Result stored to byte_to_hex_buffer
227 \param value byte to be converted */
228 void byte_to_hex(byte value)
229 {
230  byte_to_hex_buffer[0] = hex_digits[value >> 4]; // get upper nibble
231  byte_to_hex_buffer[1] = hex_digits[(value & 0x0F)]; // get lower nibble
232  //byte_to_hex_buffer[2] = '\0'; // add NULL at end (value is never changed and already initialized to value 0)
233 }
234 
235 /** \fn byte read_hex()
236 \brief Reads hexadecimal value from serial port
237 read 2 hex characters from the serial buffer and convert
238 them to a byte
239 \return the hexadecimal value as a byte. */
240 byte read_hex()
241 {
242  byte data;
245  data = strtol(hex_to_byte_buffer, NULL, 0);
246  return (data);
247 }
248 
249 /** \fn boolean tinyDC590B(char command)
250 \brief process commands received via serial interface. Those are the m,l commands and the basic DC590B commands
251 used for DC590B compatibility mode that allows the GUI to communicate with this sketch.
252 (basic set of DC590 commands to allow I2C communication to the LTC2947)
253 \param command the command to be decoded
254 \return true if command was recognized and decoded, false for unknown command */
255 boolean tinyDC590B(char command)
256 {
257  dc590Busy = true;// DC590 is busy
258  switch (command)
259  {
260  case 't':
261  case 'v':
262  case 'w':
263  // non supported DC590B commands
264  //'u': // this is a sub-command of 't', so no need to define it here!!!
265  break;
266  case 'x':
268  break;
269  case 'X':
271  break;
272  case 'D': // delay milliseconds
273  delay(read_hex() << 8 | read_hex());
274  break;
275  case 'g': // IO pin low
277  break;
278  case 'G': // IO pin high
280  break;
281  case 'H': // wait for MISO to go high with a timeout
282  {
283  long delay_count = 0;
284  while (1)
285  {
286  if (input(MISO) == 1) break; // MISO is high so quit
287  if (delay_count++ > MISO_TIMEOUT)
288  {
289  //Serial.print('T'); // timeout occurred. Print 'T'
290  break;
291  }
292  else delay(1);
293  }
294  }
295  break;
296  case 'L': // wait for MISO to go low with a timeout
297  {
298  long delay_count = 0;
299  while (1)
300  {
301  if (input(MISO) == 0) break; // MISO is low so quit
302  if (delay_count++ > MISO_TIMEOUT)
303  {
304  //Serial.print('T'); // timeout occurred. Print 'T'
305  break;
306  }
307  else delay(1);
308  }
309  }
310  break;
311  case 'P': // ping
312  Serial.print('P');
313  delay(5);
314  break;
315  case 'i': // send controller id string
316  pseudo_reset = 0;
317  ////////////////////////////////////////////////////
318  // CHANGED MAJOR VERSION to 2 FOR ENHANCED VERSION//
319  // CHANGED MINOR VERSION to 2 FOR TINY VERSION //
320  // added suffix to identify tiny version //
321  ////////////////////////////////////////////////////
322  //Serial.print(F("USBSPI,PIC,01,01,DC,DC590,----------------------\n"));
323  Serial.print(F("USBSPI,PIC,02,02,DC,DC590,tinyDC590-DC2574A_KIT-\n"));
324  Serial.print('\0'); // quikeval wants to read the null termination character!
325  Serial.flush();
326  dc590Busy = false;
327  break;
328  case 'I': // get controller id string
329  pseudo_reset = 0;
330  // this is DC2334 only, so we will just send its string (no read from demoboard's EEPROM here!)
331  Serial.print(F("LTC2947,Cls,D2947,01,01,DC,DC2334A,-------------\n"));
332  Serial.print('\0'); // quikeval wants to read the null termination character!
333  Serial.flush();
334  dc590Busy = false;
335  break;
336  case 'K': // Set pin state. The pin assignments are :
337  {
338  // 0: PIND2, Arduino 2
339  // 1: PIND3, Arduino 3
340  // 2: PIND4, Arduino 4
341  // 3: PIND5, Arduino 5
342  // 4: PIND6, Arduino 6
343  // 5: PIND6, Arduino 7
344  char pin_value = get_char(); // read the value
345  char pin = get_char(); // read the pin
346  digitalWrite(pin - 0x30 + 2, pin_value == '0' ? LOW : HIGH);
347  }
348  break;
349  case 'k': // Get pin state. The pin assignments are the same as for 'K':
350  {
351  char pin = get_char(); // read the pin
352  Serial.print(digitalRead(pin - 0x30 + 2));
353  }
354  break;
355  case 'j': // Set pin mode. The pin assignments are the same as for 'K':
356  {
357  char pin_value = get_char(); // read the value
358  char pin = get_char(); // read the pin
359  pinMode(pin - 0x30 + 2, pin_value == '0' ? INPUT : OUTPUT);
360  }
361  break;
362  case 'M': // change the serial mode (I2C only!)
363  switch (get_char())
364  {
365  case 'I': // I2C mode
368  break;
369  case 'S':// spi mode
372  break;
373  case 'X':// axillary I2C mode - no hardware action necessary, always available.
376  break;
377  }
378  break;
379  case 'p': // I2C stop //i2c_stop();
380  if (serial_mode != spi_mode) TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
381  break;
382  case 'Q': // Read byte in I2C mode only. Add ACK
383  if (serial_mode != spi_mode)
384  {
386  Serial.print(byte_to_hex_buffer);
387  }
388  break;
389  case 'r':
390  byte_to_hex(spi_read(0));
391  Serial.print(byte_to_hex_buffer);
392  break;
393  case 'R': // Read byte, add NACK in I2C mode
394  if (serial_mode != spi_mode)
395  {
397  Serial.print(byte_to_hex_buffer);
398  }
399  else
400  {
401  byte_to_hex(spi_read(0));
402  Serial.print(byte_to_hex_buffer);
403  }
404  break;
405  case 's': // I2C start
406  if (serial_mode != spi_mode)
407  i2c_start();
408  break;
409  case 'S': // send byte
410  if (serial_mode != spi_mode)
411  {
412  if (i2c_write(read_hex()) == 1) Serial.print('N');
413  }
414  else
415  {
416  spi_write(read_hex());
417  }
418  break;
419  case 'T': // transceive byte
420  if (serial_mode == spi_mode)
421  {
423  Serial.print(byte_to_hex_buffer);
424  }
425  break;
426  case 'Z': // line feed
427  Serial.print('\n');
428  Serial.flush();
429  // The last character the GUI sends for every transaction is always Z
430  // this means if we reached this state the GUI finished its communication
431  // with DC590 and we are not busy anymore
432  dc590Busy = false;
433  break;
434  case '\x80': // 0x80:Reset
435  if (pseudo_reset == 0)
436  {
437  delay(500); // The delay is needed for older GUI's
438  Serial.print("hello\n");
439  pseudo_reset = 1;
440  }
441  break;
442  default:
443  dc590Busy = false; // if we don't set this to false here, we have to deassert it within processCommand
444  return false; // non-DC590B command
445  }
446  return true;// processed DC590B command
447 }
448 
449 
const byte i2c_auxiliary_mode
char get_char()
Gets the character.
static uint8_t QueueIn
The queue in element.
char hex_digits[16]
hex conversion constants
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
char byte_to_hex_buffer[3]
buffer for byte to ASCII hex conversion
static uint8_t QueueOut
The queue out element.
Header File for Linduino Libraries and Demo Code.
boolean DelayAndCheckSerialData(unsigned long ms)
Delay and check serial data.
boolean dc590Busy
DC590 busy flag.
#define MISO_TIMEOUT
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
char hex_to_byte_buffer[5]
buffer for ASCII hex to byte conversion
static void byte_to_hex(byte value)
convert a Byte to two hexadecimal characters.
int8_t i2c_start()
Write start bit to the hardware I2C port.
Definition: LT_I2C.cpp:425
const byte spi_mode
static uint8_t Queue[QUEUE_SIZE]
The queue.
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
#define QUEUE_ELEMENTS
max elements in the queue
#define QUIKEVAL_GPIO
Linduino QuikEval GPIO pin (QuikEval connector pin 14) connects to Arduino pin 9. ...
Definition: Linduino.h:56
int8_t i2c_write(uint8_t data)
Send a data byte to hardware I2C port.
Definition: LT_I2C.cpp:470
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
#define input(pin)
Return the state of pin "pin".
Definition: Linduino.h:79
boolean CheckSerialData()
Determines if serial data is available and stores data in the queue.
char DequeueChar()
Dequeue character.
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
const byte i2c_mode
boolean tinyDC590B(char command)
process commands received via serial interface.
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
byte read_hex()
Reads hexadecimal value from serial port read 2 hex characters from the serial buffer and convert the...
byte serial_mode
uint8_t i2c_read(int8_t ack)
Read a data byte from the hardware I2C port.
Definition: LT_I2C.cpp:491
#define QUEUE_SIZE
queue size.
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
static void EnqueueSerialData()
Enqueue serial data.
unsigned char pseudo_reset