Direct drive of 7 segment display as fix - Page 1
Forum section: electronics / projects

author: Ba_E
author_rank: Newbie
timestamp: May 06, 2016, 10:06:12 am
content: Hello EEVblog community, my name is ReeceI have a product that uses a 7 segment 4 digit display to show info to the user, and I have been debugging the PCB for the last few weeks as I was experiencing weird problems.The latest issue I have found is that I obviously never triple check connections between datasheet and schematic. This has resulted in a some segment pins being mixed up with digit pins, resulting in ghosting and incorrectly displayed info.I have considered cutting tracks and just jumping the needed connections, or removing the drive transistors and connecting them straight to the MCU's IO pins and driving everything in the correct manner from code. The second option seems nicer as I don't want to jump 30 display boards.My concern comes from the fact that I am unsure if the MCU can handle the current. Points about the way its driven:MultiplexedResistors on segment lines 220ohmTransistors on cathodes, meant to be how its driven, with 1kohm base resistorsCommon cathode displayVcc = 5V16MHz crystalI am using an ATMega32u4 as the MCU and I the LED display is aLFD5216.So to end the whole thing I ask if the community may give me suggestions if directly driving the displayWITHOUT transistorsis possible? And if I run the risk of cooking the IC?Thanks

author: danadak
author_rank: Super Contributor
timestamp: May 06, 2016, 10:53:19 am
content: The short answer is Yes, No.Yes, its possible, but sinking the common current cannot violate thechips pin and buss ratings for current, in spec sheet.No, what are display specs for brightness vs current, there is a trade-off."Normally" one would at least supply the digit common with a transistor.When driving a transistor, say NPN sink, a base R is used to limit currentinto base. Saturation requirements generally are Ib = Icsat / 10.Segment R's, they help turn the drive into current drive vs V. Led thresholds,display to display, vary all over the map, so best to drive with something thatapproximates a current source. That's partially achieved by segment R.Regards, Dana.

author: SL4P
author_rank: Super Contributor
timestamp: May 06, 2016, 11:07:12 am
content: It sounds (not very clear), that the product is your own design & firmware...In that case you may be able to rework the display driving code to remap some of the LED pins.OK, some digit and segment pins may still need to be hot wired, but finding the best solution really needs us to see all your build info and schematics etc to propose a workable idea.

author: danadak
author_rank: Super Contributor
timestamp: May 06, 2016, 11:10:32 am
content: The Atmega limits you to 40 mA per pin allowed (thatsnot what you actually get for drive, just a limit) and 200mA for Vdd and/or Vss buss of the chip.Regards, Dana.

author: Mechatrommer
author_rank: Super Contributor
timestamp: May 06, 2016, 11:32:35 am
content: this is direct drive from attiny261 pin. maximum 7 led ON at a time [digit 8], I = 7 * 5V / 1Kohm = 35mA, ie 1 pin outputting 35mA (spec says max is 40 mA), 7 pins inputting the same 35mA, 5mA each. tested for few minutes (an hour maybe) displaying 888, mcu still alive. lets see how long it can survive in real world... hint: check your atmega datasheet for Max DC specification, its usually in the end of the pages..

author: SL4P
author_rank: Super Contributor
timestamp: May 06, 2016, 11:36:41 am
content: OP, in your original post, you mention 1k base resistors... do you have any current limiting resistors on your segment drive ?

author: dannyf
author_rank: Super Contributor
timestamp: May 06, 2016, 06:39:34 pm
content: The answer is likely depends.I have driven four digit red LED displays, the worst kind from this perspective, directly from a 5v pic, no transistors and no resistors, in a digital application.I would suppose that if you are doing some analog work, it is not advisable.

author: m98
author_rank: Frequent Contributor
timestamp: May 06, 2016, 10:52:26 pm
content: The problem you described seems to be easiest solved by remapping the pins in software.

author: SL4P
author_rank: Super Contributor
timestamp: May 06, 2016, 10:57:15 pm
content: Quote from: m98 on May 06, 2016, 10:52:26 pmExcept he may have mixed up the segments & cathodes on the PCB, so the common segments might run across comm cathodes instead.A bit messy without seeing his design and build notes.

author: Mechatrommer
author_rank: Super Contributor
timestamp: May 07, 2016, 05:35:36 am
content: Quote from: m98 on May 06, 2016, 10:52:26 pmits cleaner in code if one can set all cathodes at the same time, such as...Code:// declare cathode (gnd) mapbyte digit = {0b00001000, /* 0 */0b00111011, /* 1 */0b00100100, /* 2 */0b00100001, /* 3 */0b00010011, /* 4 */0b01000001, /* 5 */0b01000000, /* 6 */0b00101011, /* 7 */0b00000000, /* 8 */0b00000001, /* 9 */0b01111111 /*nil*/};...void ShowDigit(byte num, byte place) {// clear all anodesClearBit(PORTA, 0);ClearBit(PORTA, 1);ClearBit(PORTA, 2);ClearBit(PORTA, 3);// show the digitPORTB = digit; // set cathodeSetBit(PORTA, place); // set anode};instead of setting cathode pin individually in 7 lines of code. so for example if your cathode pins scattered around PORTA and PORTB, then you cant make the above kind of code. so for some people, sometime simply remapping pins in software is not a neat solution.

author: SL4P
author_rank: Super Contributor
timestamp: May 07, 2016, 07:05:35 am
content: OP... have your read or tried any of the suggestions above?Can we help you, or should we just walk away?

author: Ba_E
author_rank: Newbie
timestamp: May 07, 2016, 09:08:30 am
content: Quote from: SL4P on May 07, 2016, 07:05:35 amHi, sorry I was away from the net for a while.I have read through all your suggestions.To answer a few of your questions, I do have resistors on the segment lines 220 ohms, first thing on the list.I will get the related code and board info up today.

author: Ba_E
author_rank: Newbie
timestamp: May 07, 2016, 09:14:06 am
content: Quote from: SL4P on May 06, 2016, 11:07:12 amIt is my own design, the board uses SMD parts, 0805 resistors and SOT-32 transistors, so I thought its possible to work a resistor across the transistor pads. So I do expect a slight bit of re wiring.

author: Ba_E
author_rank: Newbie
timestamp: May 07, 2016, 08:45:15 pm
content: Hi everyone,In have added the code that is related to the firmware that I have written. Also the image is an attachment that is on the post.The first is the array of the ports, this was done originally for the mixed-up ports of the 32u4, this means that I will be able to change the code to match the re-mapped pins on the hardware.From the below code you can also gather where I have the pins attached.Code:uint16_t port_set[] = {// for the segments(uint16_t) &PORTF,(uint16_t) &PORTF,(uint16_t) &PORTF,(uint16_t) &PORTF,(uint16_t) &PORTF,(uint16_t) &PORTF,(uint16_t) &PORTE,(uint16_t) &PORTC};uint16_t port_digit[] = {// for digits(uint16_t) &PORTB,(uint16_t) &PORTB,(uint16_t) &PORTB,(uint16_t) &PORTB};The display is run using a timer, so the refresh rate is pretty fast and adaptable, except I cannot go below about 40 on the OCR or I miss stuff on the other hardware input interrupts.The code that handles the arrays is pretty much as stock standard as anyone would write a multiplexed code, turns on digits, sets the segments, waits a brief mS, then moves on. Also the way its written allows nice animation.I am using timer three on the 32u4 in CTC mode. The code that is executed from the ISR is set_seg_data();Code:void display_digit(int digit) {//clear the display segmentfor (int a = 0; a < 8; a++) {volatile uint8_t *BIT = (volatile uint8_t *)port_set;*BIT &= ~(set);// digitalWrite(set, LOW);}for (int i = 0; i < 8; i++) { //loop checks to turn on a segmentint8_t bitset = 0;volatile uint8_t *BIT = (volatile uint8_t *)port_set;bitset = digit & (1 << i);if (bitset) { //turn on segments needed*BIT |= set;}else {*BIT &= ~(set);}}}void set_seg_data() {if (q < Q) {volatile uint8_t *bitt = (volatile uint8_t*)port_digit;*bitt |= digit;// note 1display_digit(display_data);delay(1);*bitt &= ~(digit);// note 1}q++;q = q % 4;display_digit(0); //removes the ghosting effect}NOTE 1: I will probably switch the two instructions at this point If I remove my NPN transistors.Also another question, does direct driving have an effect on battery powered devices. Also some more info, when running the whole circuit draws about 35-50mA when the display is working, I don't know if this might help with the suggestions you might give.Quote from: Mechatrommer on May 07, 2016, 05:35:36 amMechatrommer, as you can see my code is similar to how you wrote yours, so getting mine to remap in software will be clean

author: Mechatrommer
author_rank: Super Contributor
timestamp: May 07, 2016, 09:25:12 pm
content: Quote from: Ba_E on May 07, 2016, 08:45:15 pmno! yours is 16 loop of dont know what code iterations. mine is 2 or at most 6 of nearly atomic code... and you got alot of resources there just for the display map (i guess) by looking at your arduino code. my attiny261 is 1K flash and 1K ram only, good enough for processing a stepper motion...

author: Ba_E
author_rank: Newbie
timestamp: May 08, 2016, 10:27:37 am
content: Quote from: Mechatrommer on May 07, 2016, 09:25:12 pmThe two functions use 1.3k of flash and 300 bytes of ram when used on there own. Also it has to have multiple iterations because of the incomplete ports on the 32u4, i.e. there are no 8bit long ports so I can't just write it like yours or any other 7 segment display stuff.Also I am only using arduino delay and serial for the USB stack stuff, everything else us AVR portable code.

author: dannyf
author_rank: Super Contributor
timestamp: May 08, 2016, 11:01:44 am
content: I took a different approach.I would define led pins (both segments and digits) individually, like this:Code://Pin12/Dig1 on RA1#define DIG1_PORT PORTA#define DIG1_DDR TRISA#define DIG1 (1<<1)//Pin11/SegA on RA0#define SEGA_PORT PORTA#define SEGA_DDR TRISA#define SEGA (1<<0)The function to update the display is quite simple:Code://display vRAM / buffervoid display(void) {static uint8_t dig=0; //current digit to be displayedDIGALL_OFF(); //all digits are off//light up the segs//segment convention: SEGDP.SEGG.SEGF.SEGE.SEGD.SEGC.SEGB.SEGAif (vRAM&0x80) SEG_ON(SEGDP_PORT, SEGDP); else SEG_OFF(SEGDP_PORT, SEGDP);if (vRAM&0x40) SEG_ON(SEGG_PORT, SEGG); else SEG_OFF(SEGG_PORT, SEGG);if (vRAM&0x20) SEG_ON(SEGF_PORT, SEGF); else SEG_OFF(SEGF_PORT, SEGF);if (vRAM&0x10) SEG_ON(SEGE_PORT, SEGE); else SEG_OFF(SEGE_PORT, SEGE);if (vRAM&0x08) SEG_ON(SEGD_PORT, SEGD); else SEG_OFF(SEGD_PORT, SEGD);if (vRAM&0x04) SEG_ON(SEGC_PORT, SEGC); else SEG_OFF(SEGC_PORT, SEGC);if (vRAM&0x02) SEG_ON(SEGB_PORT, SEGB); else SEG_OFF(SEGB_PORT, SEGB);if (vRAM&0x01) SEG_ON(SEGA_PORT, SEGA); else SEG_OFF(SEGA_PORT, SEGA);//turn on the digswitch (dig) {case 0: DIG_ON(DIG1_PORT, DIG1); break;case 1: DIG_ON(DIG2_PORT, DIG2); break;case 2: DIG_ON(DIG3_PORT, DIG3); break;case 3: DIG_ON(DIG4_PORT, DIG4); break;}//advance to the next digitdig=(dig==3)?0:(dig+1);}vRAM[] is the display buffer and it contains the information to be displayed.You can call the display function from within an isr or in the main loop. It keeps tracks of the digit being displayed.I have used on many mcus with no problem - so it should work on arduino as well.

author: Ba_E
author_rank: Newbie
timestamp: May 08, 2016, 11:27:06 am
content: dannyfThanks for sharing the way you have done it, appreciate the effort on your part and othersMy code is similar in that it keeps track of its digit that its displaying between ISR executions. I also have a global array that other functions write to and is called in set_seg_data(); Its just going to be too many defines and such and a complete rework of the code.To those helping on the thread, the problem I am having is with the hardware, not the software, I know how seven segments work and how to drive them. what I am seeking is a recommendation on how to drive the display without the use of transistors. This is meant in the nicest way possible.

author: dannyf
author_rank: Super Contributor
timestamp: May 08, 2016, 01:28:24 pm
content: If i were to write your code, I would think about trimming fat: there are a lot of loops, 16-bit types, remapping, "%" operations, etc.; The piece I posted takes about 150 cycles to run - and it still be optimized as it was written as a generic demo routine. I would be surprised if your code takes less than 500 cycles to run through.and I would also be concerned about the amount of hardwiring that goes into your code - it makes reusing the code for future projects difficult.not to mention the scarcity of comments: you wouldn't remember what the code does 6 months from now.QuoteI think that has been given, a while back. Basically, assuming you use regular leds, direct drive is OK. I tend to put the resistors on the segments rather than on the digits - putting resistors on the digits can cause variable brightness depending on the number of segments that are lit.