I'm controlling a dual, common anode 14-segment display (HDSP-A22C). The problem is that this display features two characters in a single package, making each separate segment pin shared between the two characters. That means you can't show individual values on the display without either using 30 transistors or switching between the two common anodes at high frequency.
The solution I found for this was to use an unused GPIO pin on my expander which tells which common anode should be switched (0 means left is on, 1 right). After I built this circuit I noticed how the two characters I write to the expander were interfering with eachother. After some experimenting I found out this is happening because when you write 16 bits, it's split into two bytes and once a byte reaches the expander it's immediately written to the actual pins. So IO register A is already changed while the old output is still on IO register B. The bottom half of the character is always visible on both characters.
When I write 16 bits I need the I/O expander to wait for all the bits (both bytes) to be received before the output is placed on the pins. I couldn't find anything about this functionality in the datasheet of the MCP23017 so I'm guessing it's not possible?
Are there any other solutions I can implement to synchronize the registers?
Other solutions I came up with were to refresh at a lower frequency (adding a 10ms delay between the characters). This works but it's not a nice solution. The frequency is low enough to notice and it technically doesn't solve the problem, it's just less noticable. I also tried clearing the registers before writing the new character (so just writing all zeroes to both registers before putting my new character on it). This solves the problem but the display runs at a lower duty cycle (25% for each character). It's also just a work-around and not an actual solution, but if nothing better comes up I'm doing this.
You can no longer claim to be a newbie to the forum. Read the forum guide in the sticky post. We need your schematic, your sketch and links to your components. We should not have to ask you for these things.
The effect you have noticed is called "ghosting" or "bleeding" and is a common problem for newbies attempt to implement multiplexed displays for the first time. Normally it is easy to fix.
Sorry I didn't post the schematic before, I was in a hurry and didn't have one on hand. I also don't see how the other post I made is cross-posting, because it's a totally unrelated problem (programming data structures is something entirely different last time I checked) that happens to be in the same project. I don't really understand your hostility.
I'm not able to simply 'share my sketch' because I'm not posting five files here. All interesting code happens in just four lines which I clearly explained in my original post. If you absolutely need them, here they are. The send function is permanently being called in a loop. resolveCharacter() returns a 16-bit encoding of the character and it's nothing more than a mapping of bits 1-16 to outputs 1-16 of the expander chip. The least significant bit is mapped to GPA0 (see scheme) and toggles the common anode. Note that because of my wiring, the outputs are inverted (if I send a 1, that segment turns off)
However that may be, you need to correct your sketch of the circuit - the part regarding the PNP transistors - before I am going to take your problem seriously.
I've been trying to understand how the transistors in your circuit are supposed to work, but I can't figure it out. Perhaps you made some errors when you drew it? It looks like GPA0 is supposed to control which of the two common anodes is connected to 5V. One of the PNP emitters is connected directly to 5V, so when switched on by GPA0 being LOW, the common anode connected to its collector will also be connected to 5V. But the other PNP's emitter is only connected to 5V via a 10K. So when GPA0 is HIGH, the other common anode is connected to 5V but only via 10K?
Assuming you simply drew it wrong, and it is in fact wired correctly, I believe this is what is causing your ghosting. To avoid ghosting, you need to be able to control both common anodes independantly, so you can switch them both off while the pins connected to the cathodes are being updated. After that's done, you can switch one of the two anodes on. But with GPA0 controlling both common anodes, you have no way to switch both off. This means one or the other anodes is on while the cathode pins are being updated, causing the ghosting.
I probably drew it incorrectly as I copied the schematic and mirrored/rotated and whatever to fit it in with the rest. This is the original schematic an this is how it's wired as well (it works as I should expect so I guess this is right):
The 1k was a correction for the resistor below it, not the one to the left.
What you're saying about controlling both pins independently makes sense to me, however I'm not sure on how to implement that. I do have one bit/pin left on my expander (namely the one I have currently assigned to the decimal point segment, which I'm not gonna use and if I'd change my mind I could still use an Arduino pin instead). Are you saying that I should use both of these? Isn't that going to reduce my duty cycle just like writing all zeroes before writing the character encoding does? If I first have to write a byte to turn both anodes off, I'm sending data to the chip four times in one cycle, which is what I do now. I'd prefer to only do it twice (once for each character) but if that's not possible, that's too bad. Or should I control the common anodes to turn off using a free Arduino pin instead? Which would roughly look like this in code:
void send() {
digitalWrite(controlPin, 0); //Turn both common anodes off
mcp.writeGPIOAB(~characterEncoding); //Write the data to the expander
digitalWrite(controlPin, 1); //Turn both common anodes back on
}
I would need a similar piece of code to make the characters alternate just like it works now.
Yes, if you use another pin from the expander to control the two PNPs separately, that will increase the overheads by requiring more writes to the expander for each multiplexing cycle. But the mcp32017 is capable of 400MHz speed, I think, so you could maybe use that to compensate. Or, as you suggested, use 2 Arduino pins to control the PNPs. Either way, you won't need that NPN as an invertor.
digitalWrite(controlPin, 0); //Turn both common anodes off
Don't understand that, as I said, you need individual control of each PNP/common anode.
PaulRB:
Don't understand that, as I said, you need individual control of each PNP/common anode.
The idea is to turn the display off while data is being written right? I actually made a mistake writing that, in my head I had the following code:
void send() {
digitalWrite(controlPin1, 0); //Turn common anode 1 off
mcp.writeGPIOAB(~characterEncoding1); //Write the data to the expander
digitalWrite(controlPin1, 1); //Turn common anode 1 back on
digitalWrite(controlPin2, 0); //Turn common anode 2 off
mcp.writeGPIOAB(~characterEncoding2); //Write the data to the expander
digitalWrite(controlPin2, 1); //Turn common anode 2 back on
}
This turns each common anode off while data is being written, right?
I also found no real increase in brightness from increasing the i2c speed to 400MHz, but I will try to test that some more, I might have made a mistake here or there.
My 400KHz (not 400MHz, sorry!) suggestion was to use if you were controlling both PNPs with expander pins, to help reduce the "dead time" when neither digit was lit. Not as important if using Arduino pins, so not surprised it makes no apparent difference.
Looking at your code above, I would not expect this to cure the ghosting problem. At no point in time are both PNP switched off. You are still sending data when one of them is on.
Try this:
void send() {
mcp.writeGPIOAB(~characterEncoding1); //Write the data to the expander
digitalWrite(controlPin1, LOW); //Turn common anode 1 on
delay(5);
digitalWrite(controlPin1, HIGH); //Turn common anode 1 off
mcp.writeGPIOAB(~characterEncoding2); //Write the data to the expander
digitalWrite(controlPin2, LOW); //Turn common anode 2 on
delay(5);
digitalWrite(controlPin2, HIGH); //Turn common anode 2 off
}