GithubHelp home page GithubHelp logo

analogdevicesinc / linduino Goto Github PK

View Code? Open in Web Editor NEW
99.0 16.0 100.0 18.34 MB

Code for the Linduino, An Arduino Uno-based board that is compatible with many Analog Devices evaluation boards

License: Other

C++ 63.39% C 36.48% HTML 0.01% Python 0.09% Makefile 0.01% Shell 0.02% Batchfile 0.02% CSS 0.01% VBScript 0.01%

linduino's Introduction

Linduino Read Me

Overview

The Linduino (Demonstration Circuit DC2026) is an Arduino-based controller board used for developing and distributing firmware libraries and example code for Analog Devices products. As shipped, the Linduino functions as a bridge between evaluation GUI software and supported product evaluation boards. It can also be reprogrammed with product-specific example code, included in the Linduino Github repository.

Each Linduino-supported product includes an example main program, defined in the LTSketchbook/Part Number folder. Driver code is defined in the LTSketchbook/libraries folder, and is intended to be used directly in the customer's platform.

User Guide & Downloads

A Detailed User Guide for the Linduino, showing how to set up the hardware and use the software tools is available here.

Purchase

For details on where and how to purchase the Linduino, please visit the Analog Devices website or any of Analog Devices authorized distribution partners.

How to run an example code

  1. Download and run Arduino.exe (Version 1.8.5). You can find the installer here.
  2. Download LTSketchbook.
  3. Open the Arduino IDE and go to Files → Preferences and add the LTSketchbook location.
  4. It is the location where you have saved the LTSketchbook. Check the ‘Use External editor’ option to edit your code files in an external text editor like Notepad++ (optional). Click OK and reopen the Arduino IDE. The Preferences will not be set unless the IDE is reopened.
  5. Connect Linduino to your PC through a USB port. Wait till your computer identifies the board as a COM Port.
  6. Select the Serial Port on the Arduino IDE ­from File → Port.
  7. Navigate to the example code in Part Number folder from File options.
  8. Click the Compile button to compile the code. Click the Upload button to upload the code into Linduino.
  9. Open the Arduino serial monitor and set the baud rate to 115200 to see the menu options.

linduino's People

Contributors

aaronschultz47 avatar adi-patrick avatar adimike avatar gregoryjjb avatar jothishjoseph avatar ma-la-vi-ka avatar malavikasajikumar avatar mpeters76 avatar mthoren-adi avatar pranavi-raiker avatar sunnyanalog avatar vravind704 avatar wsapia-adi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linduino's Issues

LTC681x - idea to improve rdstat, rdaux, and rdcv

Below are improvements to ltc681x_rdstat, ltc681x_rdaux, ltc681x_rdcv. I carefully tested this with DC2259 (LTC6811). This will resolve issue #45

I have used #47 and #58 in the code below.

This change will:

  • Reduce code size by 280 bytes
  • Reduce code lines from 171 lines to 108 lines (This improves readability a lot)

rdcv

uint8_t LTC681x_rdcv(uint8_t reg, uint8_t total_ic, cell_asic *ic) {
    int8_t pec_error = 0;
    uint8_t cell_data[NUM_RX_BYT * total_ic];
    uint8_t c_ic = 0;

    // Executes once for each of the LTC6811 cell voltage registers 
    for (uint8_t cell_reg = reg; cell_reg < ic[0].ic_reg.num_cv_reg + 1; cell_reg++) {
        if (cell_reg == REG_ALL) cell_reg++; // Start with REG_1 = 1

        LTC681x_rdcv_reg(cell_reg, total_ic, cell_data);

        for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) {
            c_ic = isospi_reverse_check(total_ic, current_ic, ic->isospi_reverse);
            pec_error = pec_error + parse_cells(c_ic, cell_reg, cell_data,
                                                &ic[c_ic].cells.c_codes[0],
                                                &ic[c_ic].cells.pec_match[0]);
        }
        if (reg == REG_1) break;
        if (reg == REG_2) break;
        if (reg == REG_3) break;
        if (reg == REG_4) break;
        if (reg == REG_5) break;
        if (reg == REG_6) break;
    }
    LTC681x_check_pec(total_ic, CELL, ic);

  return(pec_error);
}

rdaux

int8_t LTC681x_rdaux(uint8_t reg, uint8_t total_ic, cell_asic *ic) {   
    uint8_t data[NUM_RX_BYT * total_ic];
    int8_t pec_error = 0;
    uint8_t c_ic = 0;

    // Executes once for each of the LTC681x aux voltage registers 
    for (uint8_t gpio_reg = reg; gpio_reg < ic[0].ic_reg.num_gpio_reg + 1; gpio_reg++) {
        if (gpio_reg == REG_ALL) gpio_reg++; // Start with REG_1 = 1

        LTC681x_rdaux_reg(gpio_reg, total_ic, data);

        for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) {
            c_ic = isospi_reverse_check(total_ic, current_ic, ic->isospi_reverse);
            pec_error = parse_cells(c_ic, gpio_reg, data,
                                    &ic[c_ic].aux.a_codes[0],
                                    &ic[c_ic].aux.pec_match[0]);
        }

        if (reg == REG_1) break; // skip Register B if only Register A was selected.
    }
    LTC681x_check_pec(total_ic, AUX, ic);

    return (pec_error);
}

rdstat

int8_t LTC681x_rdstat(uint8_t reg, uint8_t total_ic, cell_asic *ic) {
    const uint8_t STAT_IN_REG = 3;
    uint8_t data[NUM_RX_BYT * total_ic];
    uint8_t data_counter = 0;
    int8_t pec_error = 0;
    uint16_t parsed_stat;
    uint16_t received_pec;
    uint16_t data_pec;
    uint8_t c_ic = 0;

    for (uint8_t stat_reg = reg; stat_reg < 3; stat_reg++) {
        if (stat_reg == REG_ALL) stat_reg++; // Start with REG_1 = 1
        data_counter = 0;

        LTC681x_rdstat_reg(stat_reg, total_ic, data);
        
        // Executes for every LTC681x in the daisy chain
        for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) {
            c_ic = isospi_reverse_check(total_ic, current_ic, ic->isospi_reverse);
            if (stat_reg == REG_1) {
                for (uint8_t current_stat = 0; current_stat< STAT_IN_REG; current_stat++) // This loop parses the read back data into Status registers, 
                {																		 // it loops once for each of the 3 stat codes in the register
                    parsed_stat = data[data_counter] + (data[data_counter + 1] << 8);       //Each stat codes is received as two bytes and is combined to create the parsed status code
                    ic[c_ic].stat.stat_codes[current_stat] = parsed_stat;
                    data_counter += 2;
                    // data[0:1]   -> STBR0 og STBR1
                    // data[2:3]   -> STBR2 og STBR3
                    // data[4:5]   -> STBR4 og STBR5
                }
            } else if (stat_reg == REG_2) {
                parsed_stat = data[data_counter] + (data[data_counter + 1] << 8);          //Each stat is received as two bytes and is combined to create the parsed status code
                ic[c_ic].stat.stat_codes[3] = parsed_stat; // STBR0 og STBR1 16-bit value for Digital power supply
                data_counter += 2;

                //ic[x].stat.flags[0] = STBR2: [C4OV, C4UV, C3OV, C3UV, C2OV, C2UV, C1OV, C1UV]
                //ic[x].stat.flags[1] = STBR3: [C8OV, C8UV, C7OV, C7UV, C6OV, C6UV, C5V, C5UV]
                //ic[x].stat.flags[2] = STBR4: [C12OV, C12UV, C11OV, C11UV, C10OV, C10UV, C9OV, C9UV]
                ic[c_ic].stat.flags[0] = data[data_counter++];
                ic[c_ic].stat.flags[1] = data[data_counter++];
                ic[c_ic].stat.flags[2] = data[data_counter++]; 
                ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02) >> 1; // Multiplexer self test status, 1 means failure.
                ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01; // Thermal shutdown status
            }

            // Check for PEC mismatch
            received_pec = (data[data_counter] << 8) + data[data_counter + 1];
            data_pec = pec15_calc(6, &data[current_ic*NUM_RX_BYT]);
            data_counter += 2;
        
            if (received_pec != data_pec) {
                pec_error = -1;                         //The pec_error variable is simply set negative if any PEC errors
                ic[c_ic].stat.pec_match[stat_reg - 1] = 1;  //are detected in the received serial data 
            } else {
                ic[c_ic].stat.pec_match[stat_reg - 1] = 0;
            }
        }

        if (reg == REG_1) {
            break; // skip Register B if only Register A was selected.
        }
    }

    LTC681x_check_pec(total_ic, STAT, ic);
    return (pec_error);
}

not able to read adc2497

Hello,

I am trying to read LTC2497 with my esp32 with esp-idf framework but most of time it miss the acknowledgement can you suggest the code.

I have write below code for read function:

int8_t i2c_read_block_data(uint8_t address, uint8_t command, uint8_t length, uint8_t *values)
{
    uint8_t i = (length - 1);
    int8_t ret = 0;

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();

    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, address << 1 | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, command, true);
    i2c_master_stop(cmd);
    vTaskDelay(100 / portTICK_PERIOD_MS);
    esp_err_t err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);

    if (err != ESP_OK)
    {
        printf("Fail to begin 1 \n");
        return (1);
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);

    cmd = i2c_cmd_link_create();    
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, address << 1 | I2C_MASTER_READ, true);
    i2c_master_read(cmd, values, length, I2C_MASTER_ACK);
    i2c_master_stop(cmd);
    vTaskDelay(100 / portTICK_PERIOD_MS);
    err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);

    if (err != ESP_OK)
    {
        printf("Fail to begin 2 \n");
        return (1);
    }

    return (0); // Successful
}

above function i have written in LT_I2C_Wire.c can you please suggest the solution.

controller: ESP32S3
Framework: ESP-IDF
Supply: 3.3 V
Connection : I2C (SDA, SCL)
REF+ : 3.3 V
REF- : GND
Address: 0x14 [CA0 , CA1 , CA 2 = LOW ]
COM : GND

i am trying to read in CH0 address 0xB0

Thanks,
Fenil

Fix for compiler warning in LTC681x.cpp

In line 665 in LTC681x.cpp this line gives a compiler warning for undefined behaviour:

parsed_stat = data[data_counter++] + (data[data_counter++]<<8);

Changing this to:

parsed_stat = data[data_counter] + (data[data_counter+ 1]<<8);
data_counter = data_counter + 2;

resolves the warning.

LTC6810 - 7th Cell is not addressable

FILE: "LTC6810.cpp"

Seventh Cell or in this case CELL 0 is not addressable see the function.
If you pass in the "int Cell" with "0" the condition "else if (Cell ==0)" will never been called.

/* Helper function to set discharge bit in CFG register */
void LTC6810_set_discharge(int Cell, //The cell to be discharged
						   uint8_t total_ic, //Number of ICs in the daisy chain 
						   cell_asic *ic //A two dimensional array that will store the data
						   )
{
	for (int i=0; i<total_ic; i++)
	{
		if (Cell<7)
		{
		  ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (1<<(Cell-1));
		}
		else if (Cell ==0)
		{
		Serial.println("Hello");
		  ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (0x80);
		}
	}
}

may change to...

/* Helper function to set discharge bit in CFG register */
void LTC6810_set_discharge(int Cell,		 //The cell to be discharged
						   uint8_t total_ic, //Number of ICs in the daisy chain
						   cell_asic *ic	 //A two dimensional array that will store the data
)
{
	for (int i = 0; i < total_ic; i++)
	{
		if (Cell < 7 && Cell != 0)
		{
			ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (1 << (Cell - 1));
		}
		else if (Cell == 0)
		{
			ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (0x80);
		}
	}
}

LTC6813 aux channels are configured wrong (data for GPIO9, VREF2 and UVOV flags are never read)

I would think that:

ic[cic].ic_reg.aux_channels=9; // LTC6813

Should be:

ic[cic].ic_reg.aux_channels=12; // LTC6813

Because

  • a_codes[0] = GPIO1
  • a_codes[1] = GPIO2
  • a_codes[2] = GPIO3
  • a_codes[3] = GPIO4
  • a_codes[4] = GPIO5
  • a_codes[5] = VREF2
  • a_codes[6] = GPIO6
  • a_codes[7] = GPIO7
  • a_codes[8] = GPIO8
  • a_codes[9] = GPIO9
  • a_codes[10] = Reserved
  • a_codes[11] = UVOV flags for C13 to C18

This is how a_codes is defined in LTC681x.h

/*! AUX Reg Voltage Data structure */
typedef struct
{
  uint16_t a_codes[9]; //!< Aux Voltage Codes
  uint8_t pec_match[4]; //!< If a PEC error was detected during most recent read cmd
} ax;

This contradicts the example code from DC2350AB. I would expect a overflow when i > 8, was this code ever tested?

void print_aux(uint8_t datalog_en)
{
  for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++)
  {
    if (datalog_en == 0)
    {
      Serial.print(" IC ");
      Serial.print(current_ic+1,DEC);
      for (int i=0; i < 5; i++)
      {
        Serial.print(F(" GPIO-"));
        Serial.print(i+1,DEC);
        Serial.print(":");
        Serial.print(BMS_IC[current_ic].aux.a_codes[i]*0.0001,4);
        Serial.print(",");
      }
      
      for (int i=6; i < 10; i++)
      {
        Serial.print(F(" GPIO-"));
        Serial.print(i,DEC);
        Serial.print(":");
        Serial.print(BMS_IC[current_ic].aux.a_codes[i]*0.0001,4);        
      }

      Serial.print(F(" Vref2"));
      Serial.print(":");
      Serial.print(BMS_IC[current_ic].aux.a_codes[5]*0.0001,4);
      Serial.println();
      
      Serial.print(" OV/UV Flags : 0x");
      Serial.print((uint8_t)BMS_IC[current_ic].aux.a_codes[11],HEX);
      Serial.println();
    }
    else
    {
      Serial.print(" AUX, ");

      for (int i=0; i < 12; i++)
      {
        Serial.print((uint8_t)BMS_IC[current_ic].aux.a_codes[i]*0.0001,4);
        Serial.print(",");
      }
    }
  }
 Serial.println("\n");
}

LTC681x_rdcv incrementing pointer to cell data

In code snippet below parse_cells() is incrementing cell_data pointer, &cell_data[8*c_ic], this is done inside parse_cells() function again hence should only be done once.

if (reg == 0)
{
	for (uint8_t cell_reg = 1; cell_reg<ic[0].ic_reg.num_cv_reg+1; cell_reg++) //Executes once for each of the LTC681x cell voltage registers
	{
		LTC681x_rdcv_reg(cell_reg, total_ic,cell_data );
		for (int current_ic = 0; current_ic<total_ic; current_ic++)
		{
		if (ic->isospi_reverse == false)
		{
		  c_ic = current_ic;
		}
		else
		{
		  c_ic = total_ic - current_ic - 1;
		}
		pec_error = pec_error + parse_cells(current_ic,cell_reg, cell_data,
											&ic[c_ic].cells.c_codes[0],
											&ic[c_ic].cells.pec_match[0]);
		}
	}
}

else
{
	LTC681x_rdcv_reg(reg, total_ic,cell_data);

	for (int current_ic = 0; current_ic<total_ic; current_ic++)
	{
		if (ic->isospi_reverse == false)
		{
		c_ic = current_ic;
		}
		else
		{
		c_ic = total_ic - current_ic - 1;
		}
		pec_error = pec_error + parse_cells(current_ic,reg, &cell_data[8*c_ic],
										  &ic[c_ic].cells.c_codes[0],
										  &ic[c_ic].cells.pec_match[0]);
	}
}

Fix would be to simply pass in cell_data argument without incrementing,

pec_error = pec_error + parse_cells(current_ic,reg, cell_data, &ic[c_ic].cells.c_codes[0], &ic[c_ic].cells.pec_match[0]);

LTC681x_reset_crc_count does not use data which says how many registers are available.

This is what the function looks like right now:

/* Helper Function to reset PEC counters */
void LTC681x_reset_crc_count(uint8_t total_ic, //Number of ICs in the system
							 cell_asic *ic //A two dimensional array that stores the data
							 )
{
	for (int current_ic = 0 ; current_ic < total_ic; current_ic++)
	{
		ic[current_ic].crc_count.pec_count = 0;
		ic[current_ic].crc_count.cfgr_pec = 0;
		for (int i=0; i<6; i++)
		{
			ic[current_ic].crc_count.cell_pec[i]=0;
		
		}
		for (int i=0; i<4; i++)
		{
			ic[current_ic].crc_count.aux_pec[i]=0;
		}
		for (int i=0; i<2; i++)
		{
			ic[current_ic].crc_count.stat_pec[i]=0;
		}
	}
}

We can make it more general like this:

/* Helper Function to reset PEC counters */
void LTC681x_reset_crc_count(uint8_t total_ic, //Number of ICs in the system
							 cell_asic *ic //A two dimensional array that stores the data
							 )
{
	for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++)
	{
		ic[current_ic].crc_count.pec_count = 0;
		ic[current_ic].crc_count.cfgr_pec = 0;
		for (uint8_t i = 0; i < ic[current_ic].ic_reg.num_cv_reg; i++)
		{
			ic[current_ic].crc_count.cell_pec[i] = 0;
		
		}
		for (uint8_t i = 0; i < ic[current_ic].ic_reg.num_gpio_reg; i++)
		{
			ic[current_ic].crc_count.aux_pec[i] = 0;
		}
		for (uint8_t i = 0; i < ic[current_ic].ic_reg.num_stat_reg; i++)
		{
			ic[current_ic].crc_count.stat_pec[i] = 0;
		}
	}
}

LTC68X - I2C/SPI not shifting out data

There is a problem with the "LTC681X.cpp". It's not shifting out any data. The function that is not working is the "void LTC681x_stcomm(uint8_t len)"

a possible solution to this is this...

/* Shifts data in COMM register out over LTC681x SPI/I2C port */
void LTC681x_stcomm(uint8_t len) //Length of data to be transmitted
{
	if (len > 0)
	{
		uint8_t cmd[4];
		uint16_t cmd_pec;
		cmd[0] = 0x07;
		cmd[1] = 0x23;
		cmd_pec = pec15_calc(2, cmd);
		cmd[2] = (uint8_t)(cmd_pec >> 8);
		cmd[3] = (uint8_t)(cmd_pec);

		uint8_t data[len * 3];
		uint16_t data_pec;

		for (size_t i = 0; i < len * 3; i++)
		{
			data[i] = 0xFF;
		}

		cs_low(CS_PIN);
		spi_write_array(4, cmd);
		spi_write_array(len * 3, data);
		cs_high(CS_PIN);
	}
}

The Wire.beginTransmission() and Wire.endTransmission() should not be used together with Wire.requestFrom().

In the files:

  • Linduino/LTSketchbook/libraries/LT_I2C_Wire/LT_I2C_Wire.cpp
  • Linduino/LTSketchbook/libraries/Adafruit_FT6206_Library/Adafruit_FT6206.cpp
  • Linduino/LTSketchbook/libraries/QuikEval_EEPROM_Wire/QuikEval_EEPROM_Wire.cpp

the function Wire.requestFrom() is often used together with Wire.beginTransmission() and Wire.endTransmission().

Regardless which Wire library or which processor is used, that is not correct.

Explanation: Common-mistakes number 2 and 3.

In LTC681x_check_pec() Status Register Group B is skipped.

case STAT:
		  for (int current_ic = 0 ; current_ic < TOTAL_IC; current_ic++) {
			for (int i=0; i<ic[0].ic_reg.num_stat_reg-1; i++) { <----- Error here
			  ic[current_ic].crc_count.pec_count += ic[current_ic].stat.pec_match[i];
			  ic[current_ic].crc_count.stat_pec[i] += ic[current_ic].stat.pec_match[i];
			}
		  }

Why is there a -1 on ic[0].ic_reg.num_stat_reg it doesn't make sense to me. It seems to me this ignores PEC from one register group. Or more specifically this ignores PEC from Status Register Group B and I can find no reason from the datasheet of why this needs to be done, please correct me if I am wrong but this looks like a bug.

I would think this should look like this:

case STAT:
		  for (int current_ic = 0 ; current_ic < TOTAL_IC; current_ic++) {
			for (int i=0; i<ic[0].ic_reg.num_stat_reg; i++) {
			  ic[current_ic].crc_count.pec_count += ic[current_ic].stat.pec_match[i];
			  ic[current_ic].crc_count.stat_pec[i] += ic[current_ic].stat.pec_match[i];
			}
		  }

Numerous issues with LTC681x Open wire algorithm

I've been trying to get Open Wire check to work on the DC2259A (LTC6811) Evalution board for quite some time but it never works. So I've had to go into the code and understand each line so that I might prove that the problem is not with the code. I have found many issues and inconsistencies with the datasheet and would like to share what I've found.

Here is a post I made a year ago: https://ez.analog.com/power/f/q-a/120413/ltc6811-dc2259a-open-wire-check-not-working-with-resistors this problem is still around and I haven't found a solution.

Below are some issues I see:

  • Why does the Open wire check for cell voltages use 400mV but GPIO open wire check uses 15mV? There is no mention of this in the datasheet. Where does the "-400mV" stated in the datasheet come from?
  • There is no check for a PEC mismatch when reading the cell voltages.
  • In LTC681x_run_openwire_single the pull-up value is used to check for an open wire for the last cell when we should be using the pull-down measurement.
  • In LTC681x_run_openwire_single this check pullDwn[cic][cell] < pullUp[cic][cell] shouldn't be needed. Otherwise the datasheet should mention it.
  • In LTC681x_run_openwire_single this check openWire_delta[cic][cell]>OPENWIRE_THRESHOLD is incorrect. The threshold is also set incorrectly. This should be openWire_delta[cic][cell] < -4000
  • In LTC681x_run_openwire_single the variable conv_time is never used.
  • openWire_delta is calcuated for Cell 1 when it should only be for Cell 2 to 11. Simple fix is to change for-loop start from 0 to 1.

Numerous issues arise when looking at LTC681x_run_openwire_multi compared to LTC681x_run_openwire_single. The functions are very different when they don't need to be. Some issues above are also present in LTC681x_run_openwire_multi.

  • In LTC681x_run_openwire_multi the variable openWire_delta is uint16_t instead of int16_t so basically negative values are ignored.
  • Removing repetitive elements and sorting array elements is not needed. It is much simpler to have each index of opencells represent cell index and only take value 0 or 1. Where 1 indicates open wire.
  • For Cell 1 pull-down value is incorrectly used if (pullDwn[cic][0] == 0) when the pull-up value should be used according to the datasheets.

This code doesn't do anything useful:

if (pullDwn[cic][N_CHANNELS-2] == 0)
{  
    opencells[n] = N_CHANNELS-1;
    n++;
}

Also the code below in LTC681x_run_openwire_multi does not follow the datasheet algorithm so I'm assuming it's not correct.

if (openWire_delta[cic][cell]>OPENWIRE_THRESHOLD)
{
	opencells[n] = cell+1;
	n++;
        // Is the code below this comment really needed?
	for (int j = cell; j < N_CHANNELS-3 ; j++)                       
	{
		if (pullUp[cic][j + 2] == 0)
		{
			opencells[n] = j+2;
			n++;
		}
	}
	if((cell==N_CHANNELS-4) && (pullDwn[cic][N_CHANNELS-3] == 0))
	{
		opencells[n] = N_CHANNELS-2;
		n++;
	}
}

For LTC681x chips many functions are not returning values.

I started with fixing the PEC errors: #54 These are very big bugs.

On a second look I noticed some self-tests aren't reporting their results which basically renders the self-test useless. Since it reports no errors. Below is a list of the functions with missing returns.

Function Chip Expected Behaviour Actual Behaviour
LTC6810_rdaux() LTC6810 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6810_rdcomm() LTC6810 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6810_run_adc_redundancy_st() LTC6810 Return the total number of errors detected. Always returns 0. Which means Errors are not detected.
LTC6811_rdaux() LTC6811 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6811_rdcomm() LTC6811 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6811_run_adc_redundancy_st() LTC6811 Return the total number of errors detected. Always returns 0. Which means Errors are not detected.
LTC6811_run_adc_overlap() LTC6811 Return the total number of errors detected. Always returns 0. Which means Errors are not detected.
LTC6812_rdsctrl() LTC6812 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. returns nothing. Undefined behaviour if return value is used.
LTC6812_rdaux() LTC6812 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6812_rdcomm() LTC6812 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6812_run_adc_redundancy_st() LTC6812 Return the total number of errors detected. Always returns 0. Which means Errors are not detected.
LTC6813_rdsctrl() LTC6813 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. returns nothing. Undefined behaviour if return value is used.
LTC6813_rdaux() LTC6813 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6813_rdcomm() LTC6813 Returns 0 if no errors detected. Returns -1 if a PEC mismatch is detected. Always returns 0. Which means Errors are not detected.
LTC6813_run_adc_redundancy_st() LTC6813 Return the total number of errors detected. Always returns 0. Which means Errors are not detected.

DC2259.ino ADC/Memory Self Test ERROR

In the file:
• Linduino/LTSketchbook/Part Number/6000/6811/DC2259/DC2259.ino

On the case 12 (Run the ADC/Memory Self Test) the second argument of the function LTC6811_run_cell_adc_st should be TOTAL_IC and not ADC_CONVERSION_MODE.

Undefined behaviour in LTC681x_run_adc_overlap()

This includes LTC681x.cpp, LTC6813.cpp, LTC6812.cpp.

See below LTC681x.cpp case:

for (int cic = 0; cic<total_ic; cic++)
{
	measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
		
	if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
	{
	        error = error | (1<<(cic-1)); // <-- when cic = 0 we have a negative bitwise shift which is undefined behaviour
	}
}

On top of this I think the error counter should only count the errors.

for (int cic = 0; cic<total_ic; cic++)
{
	measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
		
	if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
	{
	        error += 1;
	}
}

In LTC681x.cpp don't use malloc/free

For example we change this:

uint8_t *cell_data = (uint8_t *) malloc((NUM_RX_BYT*TOTAL_IC)*sizeof(uint8_t));
// some code between ...
free(cell_data);

to this:

uint8_t cell_data[NUM_RX_BYT*TOTAL_IC];

When I change malloc/free everywhere in my version of LTC681x.cpp my program was 334 bytes smaller. (ATmega2560 and ATmega2561). For this use case we shouldn't really be using malloc/free if it is not a must.

Inconsistent return type for pec errors and wrong function descriptions.

parse_cells() initalises the return variable as 0 and only sets it as 1. This contradicts the documentation as seen below.

/*! 
 Helper function that parses voltage measurement registers
 @return int8_t, pec_error PEC Status.
  0: Data read back has matching PEC
 -1: Data read back has incorrect PEC 
 */
int8_t parse_cells(uint8_t current_ic, //!< Current IC
                   uint8_t cell_reg, //!< Type of register
                   uint8_t cell_data[], //!< Unparsed data
                   uint16_t *cell_codes, //!< Parsed data
                   uint8_t *ic_pec //!< PEC error
				   );

This leads to another error with functions that use parse_cells(). An example:

/*!
 Reads and parses the LTC681x cell voltage registers.
 The function is used to read the cell codes of the LTC681x.
 This function will send the requested read commands parse the data and store the cell voltages in the cell_asic structure.
 @return uint8_t, PEC Status.
  0: No PEC error detected
 -1: PEC error detected, retry read 
 */
uint8_t LTC681x_rdcv(uint8_t reg, //!< Controls which cell voltage register is read back.
                     uint8_t total_ic, //!< The number of ICs in the system
                     cell_asic *ic //!< Array of the parsed cell codes
                    );

Notice how LTC681x_rdcv() returns uint8_t yet the documentation above mentions -1: PEC error detected, retry read when it should be 1: PEC error detected, retry read

The inconsistence comes from read_68() which return a 0 or 1. I suggest you change everything to either 0 and -1 or 1.

I can create a pull request for this, but you will need to decide whether 0 and -1 should be used or 0 and 1.

LTC2309, 'display_code' always 0

Using the TSSOP variant of the LTC2309; Vdd, Vref, and REFCOMP have been connected using appropriate capacitors per page 8 of the datasheet [as opposed-to mimicking the values used on the DC1337A].

I've tried using the LTC2309.h, DC1337A.ino codes in combination-with the Datasheet-caps and DC1337A-caps; all combinations have resulted in seeing a constant 0 value being printed from the output register.

Sample code below;

// Test ability of a single ADC chip, default address 

// Source code from LTC's Linduino / <DC1337A.ino> files.
/* 
 *  REFCOMP floating
 *  AD0 - GND
 *  AD1 - GND
 *  VREF - feed-to CH0
 *  COM - GND
 */

#include "LTC2309.h" 
#include "LT_I2C.h"

// Global variables
static uint8_t uni_bipolar = LTC2309_UNIPOLAR_MODE;    //!< LTC2309 Unipolar or Bipolar mode selection
static uint8_t single_ended_differential = LTC2309_SINGLE_ENDED_MODE;    //!< LTC2309 Unipolar or Bipolar mode selection
static uint8_t i2c_address = LTC2309_I2C_ADDRESS;       //!< I2C address in 7 bit format for part
static uint8_t LTC2309_bits = 12;                      //!< Resolution (12 bits)
static float LTC2309_vref = 4.096;

// Constants
// Build the command for single-ended mode
const uint8_t BUILD_COMMAND_SINGLE_ENDED[8] = {LTC2309_CH0, LTC2309_CH1, LTC2309_CH2, LTC2309_CH3,
    LTC2309_CH4, LTC2309_CH5, LTC2309_CH6, LTC2309_CH7
                                              };        //!< Builds the command for single-ended mode

void setup() {
  // put your setup code here, to run once:
  quikeval_I2C_init();                    // Enable the I2C port
  quikeval_I2C_connect();                 // Connect I2C to main data port
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  uint8_t user_command;
  uint16_t adc_command;         // The LTC2309 command byte
  uint16_t adc_code = 0;    // The LTC2309 code
  uint8_t x, y, startcount, endcount;
  uint16_t display_code;
  float adc_voltage;
  uint8_t acknowledge = 0;       // I2C acknowledge bit

  startcount = 0;
  endcount = 7;
  adc_command = BUILD_COMMAND_SINGLE_ENDED[0] | uni_bipolar;
  acknowledge |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);     // Throws out last reading and starts CH0 conversion
  for (x = startcount; x <= endcount; x++)
  {
    adc_command = BUILD_COMMAND_SINGLE_ENDED[x % 8] | uni_bipolar; // Send channel config for the NEXT conversion to take place
    acknowledge |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);     // Throws out last reading and starts CH0 conversion
    acknowledge |= LTC2309_read(LTC2309_I2C_ADDRESS, adc_command, &adc_code);   // Read previous channel conversion (x-1) and start next one (x)

    display_code = adc_code >> (16 - LTC2309_bits);
    display_code = display_code & 0xFFF;

    Serial.print(F("  Received Code: b"));
    Serial.println(display_code, BIN);

    adc_voltage = LTC2309_code_to_voltage(adc_code, LTC2309_vref, uni_bipolar);
    Serial.print(F("  Voltage read on "));
    Serial.print(F("Ch"));
    Serial.print(x);
    Serial.print(F(": "));
    Serial.print(adc_voltage, 4);
    Serial.println(F("V"));
    Serial.println();
  }
}
// EOL

num_stat_reg is set wrong for LTC6810 and LTC6811

It should be ic[cic].ic_reg.num_stat_reg=2 exactly like LTC6813.

void LTC6811_init_reg_limits(uint8_t total_ic, //The number of ICs in the system
							cell_asic *ic  //A two dimensional array where data will be written
							)
{
  for (uint8_t cic=0; cic<total_ic; cic++)
  {
    ic[cic].ic_reg.cell_channels=12;
    ic[cic].ic_reg.stat_channels=4;
    ic[cic].ic_reg.aux_channels=6;
    ic[cic].ic_reg.num_cv_reg=4;
    ic[cic].ic_reg.num_gpio_reg=2;
    ic[cic].ic_reg.num_stat_reg=3; <---- There are only 2 Status Register Groups, not 3.
  }
}

LTC6811 Linduino code bug in open wire check FIX

There is a bug in the Linduino code for the LTC6811 code in function LTC681x_run_openwire in file LTC681x.cpp. The function crates two cell_asic structures pullUp_cell_codes and pullDwn_cell_codes but does not initialises them.

Then the function LTC681x_run_openwire calls LTC681x_rdcv in which the for cycle runs until ic[0].ic_reg.num_cv_reg. The problem is that this value has not been initialise. Thus sending unpredictable messages to the LTC which leads to code crash because the function that senda messages expects an answer from the LTC.

To fix this bug the function LTC6811_init_reg_limits(total_ic,pullUp_cell_codes); and LTC6811_init_reg_limits(total_ic,pullDwn_cell_codes); should be called to initialise register sizes on the structures that have been created before calling LTC681x_rdcv.

P.S.: This have been tested in LTC6811-2 but I think that it should be a problem for all the other chips that use this code.

unwanted ISOSPI reversal in LTC681X.CCP -bug

When daisy chaining two LTC6810 chips, and writing different DCC in the configuration registers, I observed (via reading the conf registers) the two configurations got swapped between the two chips.

The SPI direction got reversed, although I did not set the "isospi_reverse" boolean to true.

the library does some things without spi reversal, and others with reversal. This is because of bugs in the code. example:
`
for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++)
{

	if (ic->isospi_reverse == true)

	{

		c_ic = current_ic;

	}

	else

	{

		c_ic = total_ic - current_ic - 1;

	}

`

but when the isospi_reverse variable is false, you don't want to reverse the direction
problem is solved by changing all fragments above to:

`for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++)

{

	if (ic->isospi_reverse == false)         //true to false

	{

		c_ic = current_ic;

	}

	else

	{

		c_ic = total_ic - current_ic - 1;

	}`

LTC681x.cpp rdaux() writing outside ic[].aux.a_codes[] for LTC6813 when reading all registers

The length of ic[].aus.a_codes[] is 9 (see LTC681x.hpp)
/*! AUX Reg Voltage Data structure */ typedef struct { uint16_t a_codes[9]; //!< Aux Voltage Codes uint8_t pec_match[4]; //!< If a PEC error was detected during most recent read cmd } ax;
But in rdaux() there are 4 registers which get transferred (see LTC6813.cpp)
/* Helper function to initialize register limits. */ void LTC6813_init_reg_limits(uint8_t total_ic, //Number of ICs in the system cell_asic *ic // A two dimensional array that will store the data ) { for(uint8_t cic=0; cic<total_ic; cic++) { ic[cic].ic_reg.cell_channels=18; ic[cic].ic_reg.stat_channels=4; ic[cic].ic_reg.aux_channels=9; ic[cic].ic_reg.num_cv_reg=6; ic[cic].ic_reg.num_gpio_reg=4; ic[cic].ic_reg.num_stat_reg=2; } }
And in each register the parse_cells() function writes 3 values / voltages
const uint8_t CELL_IN_REG = 3;

This makes 4*3=12 values written into an array of length 9. Writing more then 9 values is correct as in Auxillary Register Group B the last value is not a GPIO but the second Reference Voltage (ic[].aux.a_codes[5]), this is very useful.
However this leads to (some of) the reserved bits getting written into ic[].aux.a_codes[10, 11] as well as some Overvoltage and Undervoltage flags. If I read the code correctly ic[].aux.a_code[9, 10, 11] will get written into ic[].stat.stat_codes[0, 1, 2], this behavior can not be intended. Have I missed something in reading the code or what would be acorrect fix? I am leaning to increasing the length of the ic[].aux.a_codes[] array to 12, but I do not know if this might conflict with other LTC681x Chips.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.