1

its my first question here and I hope I'm not stepping on anyone's tows :-)

Currently I'm working on a modular battery management system for my electric scooter, based on a ATtiny85 as a master and multiple ATtiny85 as slaves. Each slave is monitoring one cell (or a array of multiple cells in parallel) and also using this cell to power itself up. For safety it reads the voltage of the battery and reads a temperature sensor of this cell. It sends these two information via a isolated I2C bus to the master, which will analyze it and will send eventual a response if this cell should activate balancing or not.

Therefor I'm using the digispark bootloader and flashing the software using USB. The software itself I'm programming using Arduino IDE.

So far I managed to establish a good connection between the slaves using TinyWireS and the Master using TinyWireM. I'm successfully sending data from multiple slaves to the master and vise versa.

But when I remove one or more slaves from the bus somehow the reading routine will fill the not received data with the previous received data and will not write a empty line or zero.

Here is the relevant routine, where I poll through the slaves addresses and individually ask each slave for a payload of 4 bytes. The slave will separate the measured voltage and the temperature in two bytes each and will send the resulting 4 bytes separately over the I2C bus.

The master will receive the 4 separate bytes and combine them again to voltage and temperature and write them in an array at the position matching its cell-number.

for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++)  //poll data from all cells, start with cell 1 to max
  {
    int slave_add = 0x3F+cell_num;        //connect to cell, adress offset 0x3F, first cell is 0x40
    v_data[cell_num] = 0;
    t_data[cell_num] = 0;
    TinyWireM.requestFrom(slave_add, 4);  //request from selected cell 4 bytes
    while(TinyWireM.available())
    {
      v_low = TinyWireM.receive();   //read first byte as low byte of voltage
      v_high = TinyWireM.receive();  //read second byte as hight byte of voltage
      t_low = TinyWireM.receive();   //read third byte as low byte of temp
      t_high = TinyWireM.receive();  //read fourth byte as hight byte of temp

      v_data[cell_num] = 0;
      t_data[cell_num] = 0;

      v_data[cell_num] = (v_high<<8) | v_low;  //shift high byte of voltage and combine with low byte
      t_data[cell_num] = (t_high<<8) | t_low;  //shift high byte of temp and combine with low Byte

      v_high = 0;
      v_low = 0;
      t_high = 0;
      t_low = 0;
    }

A little example to demonstrate the error: On the bus are supposed to be 14 slaves (CELL_COUNT = 14) one or more slaves (lets say number 5 & 6) is having an error and is not transmitting the 4 bytes. So the master is displaying all the data of the slave on a little OLED Display. Instead of showing a 0 at the line number 5 and 6 the master displays the same value of number 4.

The first half of the display will look something like this:

4125
4035
4156
4137
4137
4137

4089

In addition you can find the full code below:

//1MHz Speed!!!!

#include <TinyWireM.h>
#include "SSD1306_minimal.h"

#define CELL_COUNT 14 //from 1 to cell amout, number of cells on bus
SSD1306_Mini oled;

uint16_t v_data[CELL_COUNT];
uint16_t v_data_max = 0;
uint16_t t_data[CELL_COUNT];
uint16_t t_data_max = 0;
char cast1[8] = {};
char cast2[8] = {};
uint8_t v_low;
uint8_t v_high;
uint8_t t_low;
uint8_t t_high;

void setup()
{
  pinMode(1, OUTPUT);     //led pinset digispark
  digitalWrite(1, LOW);   //disable led
  oled.init(0x3c);        //init oled adress 0x3c
  oled.clear();           //clear oled display
  oled.startScreen();     //start oled routine to write
  TinyWireM.begin();      //start i2c lib for com
}

void loop()
{
  v_data_max = 0;
  t_data_max = 0;

  //read received data
  for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++)  //poll data from all cells, start with cell 1 to max
  {
    int slave_add = 0x3F+cell_num;        //connect to cell, adress offset 0x3F, first cell is 0x40
    v_data[cell_num] = 0;
    t_data[cell_num] = 0;
    TinyWireM.requestFrom(slave_add, 4);  //request from selected cell 4 bytes
    while(TinyWireM.available())
    {
      v_low = TinyWireM.receive();   //read first byte as low byte of voltage
      v_high = TinyWireM.receive();  //read second byte as hight byte of voltage
      t_low = TinyWireM.receive();   //read third byte as low byte of temp
      t_high = TinyWireM.receive();  //read fourth byte as hight byte of temp

      v_data[cell_num] = 0;
      t_data[cell_num] = 0;

      v_data[cell_num] = (v_high<<8) | v_low;  //shift high byte of voltage and combine with low byte
      t_data[cell_num] = (t_high<<8) | t_low;  //shift high byte of temp and combine with low Byte

      v_high = 0;
      v_low = 0;
      t_high = 0;
      t_low = 0;
    }
  }

  for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++)  //pring voltage and temp data to oled
  {
    oled.startScreen();   //start oled routine to write
    if (cell_num<=7)      //check if first half of cells (cell number = 14) or second half
    {
      oled.cursorTo(0,cell_num-1);  //jump to right line for cell
    }
    else
    {
      oled.cursorTo(66,cell_num-8);  //jump to right line for cell
    }
    oled.printString(itoa(v_data[cell_num], cast1, 10));  //change data from int to str and print on oled
    oled.startScreen();
    if (cell_num<=7)
    {
      oled.cursorTo(30,cell_num-1);  //jump to right line for cell
    }
    else
    {
      oled.cursorTo(96,cell_num-8);  //jump to right line for cell
    }
    oled.printString(itoa(t_data[cell_num], cast2, 10));  //change data from int to str and print on oled
  }

  delay(5000);
  oled.cursorTo(0,0);
  oled.clear();
}

I hope someone can point me in the right direction to fix this problem...

2 Answers2

0

I narrowed it down a little more... In the following code the function TinyWireM is writing the data from the loop befor to the variables v_high, v_low, T_high and t_low if no new data is received. But the weired thing is, that they are not all equal, they all have the exact same value from the loop befor. So v_high (old) = v_high (new) and so on.

How can this be if they are all set using the same function, which should run 4 times, so once for each variable?

Here is the relevant part:

v_low = TinyWireM.receive();   //read first byte as low byte of voltage
v_high = TinyWireM.receive();  //read second byte as hight byte of voltage
t_low = TinyWireM.receive();   //read third byte as low byte of temp
t_high = TinyWireM.receive();  //read fourth byte as hight byte of temp
0

I found a little inconvenience in the lib TinyWireM. If you receive some data, the lib will store it in the buffer. If you read the buffer it will show the content. If there is no new data received the buffer will stay as is and you will read the exact same Data if you read the buffer again.

Therefor I changed the TinyWireM.ccp so that the buffer will be deleted if read once.

Now it will show a 0 if you read the buffer again without new received data.