| 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 */
119 char hex_to_byte_buffer[5] =
120 {
121 '0', 'x', '0', '0', '\0'
122 };
123
124
125 /** \brief buffer for byte to ASCII hex conversion */
126 char byte_to_hex_buffer[3] =
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. */
153 void EnqueueSerialData()
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. */
180 char DequeueChar()
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 {
193 EnqueueSerialData();
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 */
200 boolean CheckSerialData()
201 {
202 if (Serial.available())
203 EnqueueSerialData();
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())
218 EnqueueSerialData();
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;
243 hex_to_byte_buffer[2] = get_char();
244 hex_to_byte_buffer[3] = get_char();
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':
267 output_low(QUIKEVAL_CS);
268 break;
269 case 'X':
270 output_high(QUIKEVAL_CS);
271 break;
272 case 'D': // delay milliseconds
273 delay(read_hex() << 8 | read_hex());
274 break;
275 case 'g': // IO pin low
276 output_low(QUIKEVAL_GPIO);
277 break;
278 case 'G': // IO pin high
279 output_high(QUIKEVAL_GPIO);
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
366 serial_mode = i2c_mode;
367 quikeval_I2C_connect();
368 break;
369 case 'S':// spi mode
370 serial_mode = spi_mode;
371 quikeval_SPI_connect();
372 break;
373 case 'X':// axillary I2C mode - no hardware action necessary, always available.
374 serial_mode = i2c_auxiliary_mode;
375 quikeval_SPI_connect();
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 {
385 byte_to_hex(i2c_read(WITH_ACK));
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 {
396 byte_to_hex(i2c_read(WITH_NACK));
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 {
422 byte_to_hex(spi_read(read_hex()));
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
i2c_auxiliary_mode
const byte i2c_auxiliary_mode
Definition: DC590_subset.ino:106
get_char
char get_char()
Gets the character.
Definition: DC590_subset.ino:191
QueueIn
static uint8_t QueueIn
The queue in element.
Definition: DC590_subset.ino:146
hex_digits
char hex_digits[16]
hex conversion constants
Definition: DC590_subset.ino:113
output_high
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
byte_to_hex_buffer
char byte_to_hex_buffer[3]
buffer for byte to ASCII hex conversion
Definition: DC590_subset.ino:126
QueueOut
static uint8_t QueueOut
The queue out element.
Definition: DC590_subset.ino:149
Linduino.h
Header File for Linduino Libraries and Demo Code.
DelayAndCheckSerialData
boolean DelayAndCheckSerialData(unsigned long ms)
Delay and check serial data.
Definition: DC590_subset.ino:212
dc590Busy
boolean dc590Busy
DC590 busy flag.
Definition: DC590_subset.ino:110
MISO_TIMEOUT
#define MISO_TIMEOUT
Definition: DC590_subset.ino:100
spi_write
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
hex_to_byte_buffer
char hex_to_byte_buffer[5]
buffer for ASCII hex to byte conversion
Definition: DC590_subset.ino:119
byte_to_hex
static void byte_to_hex(byte value)
convert a Byte to two hexadecimal characters.
Definition: DC590_subset.ino:228
i2c_start
int8_t i2c_start()
Write start bit to the hardware I2C port.
Definition: LT_I2C.cpp:425
spi_mode
const byte spi_mode
Definition: DC590_subset.ino:104
Queue
static uint8_t Queue[QUEUE_SIZE]
The queue.
Definition: DC590_subset.ino:143
data
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
WITH_NACK
#define WITH_NACK
Use with i2c_read(WITH_NACK) to read without an acknowledge.
Definition: LT_I2C.h:91
QUEUE_ELEMENTS
#define QUEUE_ELEMENTS
max elements in the queue
Definition: DC590_subset.ino:137
QUIKEVAL_GPIO
#define QUIKEVAL_GPIO
Linduino QuikEval GPIO pin (QuikEval connector pin 14) connects to Arduino pin 9. ...
Definition: Linduino.h:56
i2c_write
int8_t i2c_write(uint8_t data)
Send a data byte to hardware I2C port.
Definition: LT_I2C.cpp:470
output_low
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
input
#define input(pin)
Return the state of pin "pin".
Definition: Linduino.h:79
CheckSerialData
boolean CheckSerialData()
Determines if serial data is available and stores data in the queue.
Definition: DC590_subset.ino:200
DequeueChar
char DequeueChar()
Dequeue character.
Definition: DC590_subset.ino:180
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
i2c_mode
const byte i2c_mode
Definition: DC590_subset.ino:105
tinyDC590B
boolean tinyDC590B(char command)
process commands received via serial interface.
Definition: DC590_subset.ino:255
LT_I2C.h
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
quikeval_SPI_connect
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
spi_read
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
read_hex
byte read_hex()
Reads hexadecimal value from serial port read 2 hex characters from the serial buffer and convert the...
Definition: DC590_subset.ino:240
serial_mode
byte serial_mode
Definition: DC590_subset.ino:107
i2c_read
uint8_t i2c_read(int8_t ack)
Read a data byte from the hardware I2C port.
Definition: LT_I2C.cpp:491
QUEUE_SIZE
#define QUEUE_SIZE
queue size.
Definition: DC590_subset.ino:140
quikeval_I2C_connect
void quikeval_I2C_connect(void)
Switch MUX to connect I2C pins to QuikEval connector.
Definition: LT_I2C.cpp:401
WITH_ACK
#define WITH_ACK
Use with i2c_read(WITH_ACK) to read with an acknowledge.
Definition: LT_I2C.h:90
QUIKEVAL_CS
#define QUIKEVAL_CS
QuikEval CS pin (SPI chip select on QuikEval connector pin 6) connects to Arduino SS pin...
Definition: Linduino.h:57
EnqueueSerialData
static void EnqueueSerialData()
Enqueue serial data.
Definition: DC590_subset.ino:153
pseudo_reset
unsigned char pseudo_reset
Definition: DC590_subset.ino:102