I recently started a project where I made 8, 7 segment display drivers. Each of the 8 circuits contains an attiny84 and 7 NFET's. I needed my own driver because I wanted to use individual LED's and wanted to use PWM to drive the LED's instead of wasting power with resistors. I wrote some code for the ATTiny that simulates variable duty cycle PWM with GPIO pins. Its not the best implementation but it does work. I chose to use I2C because of the 2 wires and seemingly easy setup in past projects. When I test each of the circuits on their own they work great, but when I hook all of them up I start getting weird issues where 1 or 2 of the modules will turn off. My oscilloscope is analog and about 40 years old so I cannot really see or decode the SCL and SDA line but I can see that when a module turns off randomly, the SDA line is held low and stays low. The host is a Arduino uno configured as master and the ATTiny's are all slaves.
I am using 1 byte values to do the following (change number, change duty cycle, and toggle ON/OFF). I have these arbitrary numbers listed in the code. I am using an 18awg/4 wire to carry the Vcc, Gnd, SDA, SCL and I have a capacitor across the power supply to try and filter the DC from my switching psu (which imo is pretty clean already), as well as 2.2k pull-up resistors on SDA/SCL.
The only things that are consistent are each of the circuits work exactly how I intended them to on their own, but when I hook up all 8 I start getting situations where some turn off, others have their GPIO's float which causes the transistors to be in saturation. I have a test code on the master where it cycles through each address changing the values from 0-9 and repeat.
My question is where do I start to find the problems. I have around 12ft of wire from slaves to master, but I used 18awg to negate resistive losses as much as possible. Also, I am using Attinycore from SpenceKonde and I am not sure if my codes use of micros is effecting the software implementation of i2c. I am using my arduino as ISP to program them and I am using optiboot as the bootloader. I have tried everything as to my limited knowledge so any rabbit hole to dive down I am willing. Below are the circuits, code for the Attiny, and my settings inside the ide for the attiny (fuses,etc).
#include <Wire.h>
const int g_arrayTransistors[7] = {0,1,2,3,5,7,8}; //pins of transistors for segments A-G
const byte TRANSISTOR_CONFIG[10][7] = {
{1,1,1,1,1,1,0},
{0,1,1,0,0,0,0},
{1,1,0,1,1,0,1},
{1,1,1,1,0,0,1},
{0,1,1,0,0,1,1},
{1,0,1,1,0,1,1},
{1,0,1,1,1,1,1},
{1,1,1,0,0,0,0},
{1,1,1,1,1,1,1},
{1,1,1,0,0,1,1}
};
unsigned long g_dutyCycle = 100;
unsigned long g_intervalTuple[2] = {0,0};
bool g_DisplayOn = true;
byte* g_transistorConfig = TRANSISTOR_CONFIG[0];
unsigned long g_phaseShiftTime = 0;
byte incomingByte = 0;
void setup() {
for (int i = 0; i <= 7; i++) {
pinMode(g_arrayTransistors[i], OUTPUT);
}
Wire.begin(0x19);
}
void updateState(byte incomingByte) { //returns boolean value to prevent any
if (incomingByte == 254) g_DisplayOn = false;
else if (incomingByte == 255) g_DisplayOn = true;
}
void updateTransistors(byte* g_transistorConfig, bool allOff) {
for (int i = 0; i < 7; i++) {
if (allOff) {
digitalWrite(g_arrayTransistors[i], LOW);
} else {
digitalWrite(g_arrayTransistors[i], g_transistorConfig[i]);
}
}
}
void updateGlobals(int numBytes) {
if (Wire.available() > 0) { //checks data stream for new byte to read
incomingByte = (byte) Wire.read(); //if new byte avaliable, assign to byte
if (incomingByte >= 0 && incomingByte <= 9) {
g_transistorConfig = TRANSISTOR_CONFIG[incomingByte];
} else if (incomingByte >= 254 && incomingByte <= 255) { //change the bool variable g_DisplayOn
updateState(incomingByte);
} else if (incomingByte >= 100 && incomingByte <= 200) { //pass incomingByte and change the value of unsigned long g_dutyCycle
g_dutyCycle = (unsigned long)map(incomingByte, 100, 200, 1, 3999);
}
}
}
void loop() {
Wire.onReceive(updateGlobals);
unsigned long currentTime = micros(); // take current time
if (currentTime >= g_intervalTuple[0] && currentTime <= g_intervalTuple[1]) { //if current time is in the known cycle period
if (currentTime < g_phaseShiftTime && g_DisplayOn) { //in HIGH region //start-end time need to be 0 in setup for this to be false on startup
updateTransistors(g_transistorConfig, false);
} else if (currentTime > g_phaseShiftTime || !g_DisplayOn) { //in LOW region, write ALL pins LOW
updateTransistors(g_transistorConfig, true);
}
} else {
// update global interval to this current 4 ms period.
g_intervalTuple[0] = currentTime;
g_intervalTuple[1] = currentTime + 4000;
g_phaseShiftTime = g_intervalTuple[0] + g_dutyCycle;
}
}
![](http://https://ibb.co/dWRpqW5 20201223-205704-1 hosted at ImgBB — ImgBB)