|
|
View previous topic :: View next topic |
Author |
Message |
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun Jun 24, 2012 11:39 am |
|
|
Code: | setup_timer_2(T2_DIV_BY_4, 250 , 5);
| Left to it's own devices this line causes timer2 to overflow once every 1004 us, and interrupt after every 5 overflows (i.e. roughly every 5.02ms).
Code: | clear_interrupt(int_timer2);
| You do not need this line. The compiler takes care of it for you.
This line screws up the timing by adding interrupt latency, get rid of it.
Quote: | One more thing, the 4 pins to control 7 segment common anode are shared as input also and i think it is not wise to have fast_io..
| Yes I understood the bit about the drive being passed on to other boards.
I also know that fast_io is generally bad news, but in your case it's slowing down the critical part of your scheme by a factor of about 4, I think you may have to grasp this particular nettle and deal with it. You need the speed!
Quote: | Yes, I am aware that i turn off the display every time i want to update each digit but if i exclude it, of course it is more brighter but it will just show DIGIT 8 instead of the digit that i want to display. You also well aware that i use serial to parallel technique to update every digit in rows and if i do not turn off the displays, of course we could see the data flows and because it happens so fast, we just see a NO 8..am i right?
| You are correct that must turn off the display whilst you update the cathode drives.
However, you're missing the point about speed.
The sequence goes like this:-
(1) Turn off all anodes.
(2) Update cathode drives.
(3) Turn on next anodes.
(4) Wait for next trigger to signal loop back to (1)
The more time you spend doing (2) the less there is available for (4)
The idea is to maximize (4) and minimize (1) (2) & (3).
As it stands you're spending too much time doing (2). You're also wasting time in (1) and (3), but they are minor compared to (2).
Quote: | I am really have lost idea to increase the brightness.. |
I've shown you several ways to achieve your objective.
What is it you don't understand?
Mike |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Sun Jun 24, 2012 7:01 pm |
|
|
I understood all your explanation and I did realized that NO. 2 caused the display to dim because I did a test to the see the dim effect on the display by driving the display row by row. I means I just drive the first row only and obviously, the display got brighter. But when I started to control the second row and the rest, I could see the display got more dimmer as the no of rows increases.
Instead of using 4MHz, does it would improve if i change to higher speed such as 20MHz?
Never mind, I try to improve NO.2 first. Thanks Mike.. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Mon Jun 25, 2012 1:40 am |
|
|
Yes, 20MHz would help. You will also need to make the timer2 interrupt at a lower rate. Otherwise there will be no improvement. However, you will not have answered your original question, (i.e. why is your code so much worse than the original hex?).
If you want more help you will need to post a complete compilable code for the display section only. We don't want to see the rest of your code (which you may want to keep secret anyway), but just enough to enable us to probe deeper into your display driver. In other words strip away all other code which will be a distraction.
Again I say, try measuring the voltage across one of the 100R current limiting resistors, with your code then the original hex. It will indicate how far away you are.
Mike |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Mon Jun 25, 2012 5:33 pm |
|
|
I am eager to know too why my codes unable to match with original HEX CODE. Last night I had tried to focus item NO 2 as you mentioned before by simplifying anything I could and made other items as short as possible. As a result, I managed to increase the brightness a bit. So, I had measured one of the 100R res (Using My Code) and the voltage was 0.30V @ 3mA, while the original HEX CODE was 1X brighter than mine, 0.6V @ 6mA.
The complete display code is as follow:
Code: |
#include <16F877A.h>
#fuses HS,NOWDT,NOPUT,NOBROWNOUT,NOPROTECT
#use delay(clock = 4M)
int8 display_sequence = 0;
int1 display_rate_enable = TRUE;
#byte PORTD = 0X08
#byte PORTA = 0X05
#byte PORTB = 0X06
#bit DATA_IN = PORTD.4 //(THIS ONE ONLY CONNETED TO SHIFT REGISTER ON 1ST BOARD) PIN NO 7 (SHIFT REGISTER)
//THIS BUS'S FLOW CONTROLLED BY BUFFER 1A - ONLY AVAIABLE WHEN SERIAL EN IS TRIGGERED
#bit CLK_IN = PORTD.5 //CONNECTED TO ALL BOARDS (CLOCK FOR SHIFT REGISTER)
#bit SERIAL_EN = PORTA.4 //TO ENABLE BUFFER 1A
#bit COL_LATCH_EN = PORTB.3 //TO CLOCK IN 74LS373 CHIP
//THIS BUS CONTROLLED BY BUFFER 1B - DISPLAY_EN
#bit DISPLAY_EN = PORTA.3 //TO ENABLE BUFFER 1B
const int table[11]={0b00111111,
0b00000110,
0b01011011,
0b01001111,
0b01100110,
0b01101101,
0b01111101,
0b00000111,
0b01111111,
0b01100111,
0b00000000};
// 0 1 2 3 4 5 6 7 8 9 10(OFF)
void display_current_data()
{
int8 i,y,no;
if(display_rate_enable == TRUE)
{
//TURN OFF ALL DISPLAY (COMMON ANODE)
DISPLAY_EN = 0;
COL_LATCH_EN = 0X01;
PORTD = 0b00000000;
COL_LATCH_EN = 0;
DISPLAY_EN = 0X01;
switch(display_sequence)
{
case 0:
//UPDATE COLUMN 1
display_sequence = 1;
//##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[1];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = (no >> (7 - i)) & 0X01 ;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
//TURN ON COMMON ANODE NO 1
DISPLAY_EN = 0;
COL_LATCH_EN = 0X01;
PORTD = 0b00000001;
COL_LATCH_EN = 0;
DISPLAY_EN = 0X01;
break;
case 1:
//UPDATE COLUMN 2
display_sequence = 2;
//##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[2];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = (no >> (7 - i)) & 0X01 ;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
//TURN ON COMMON ANODE NO 2
DISPLAY_EN = 0;
COL_LATCH_EN = 0X01;
PORTD = 0b00000010;
COL_LATCH_EN = 0;
DISPLAY_EN = 0X01;
break;
case 2:
//UPDATE COLUMN 3
display_sequence = 3;
//##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = (no >> (7 - i)) & 0X01 ;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
//TURN ON COMMON ANODE NO 3
DISPLAY_EN = 0;
COL_LATCH_EN = 0X01;
PORTD = 0b00000100;
COL_LATCH_EN = 0;
DISPLAY_EN = 0X01;
break;
case 3:
//UPDATE COLUMN 4
display_sequence = 0;
//##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[4];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = (no >> (7 - i)) & 0X01 ;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
//TURN ON COMMON ANODE NO 4
DISPLAY_EN = 0;
COL_LATCH_EN = 0X01;
PORTD = 0b00001000;
COL_LATCH_EN = 0;
DISPLAY_EN = 0X01;
break;
}
display_rate_enable = FALSE;
}
}
void main(void)
{
//Set-up timer 2
setup_timer_2(T2_DIV_BY_4, 250 ,5);
//Set-up port direction input or output 1 = Input 0 = Output
set_tris_a(0x00); //set Port A as an output
output_a(0xFF);
set_tris_b(0x00); //Set Port B as an output
output_b(0xFF);
set_tris_c(0x00); //Set Port C as an output
output_c(0xFF);
set_tris_d(0x00); //Set Port D as an output
output_d(0xFF);
//Set-up interrupt
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
While(TRUE)
{
display_current_data();
}
}
#INT_TIMER2
void isr_timer2()
{
if(display_rate_enable == FALSE)
{
display_rate_enable = TRUE;
}
}
|
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Jun 26, 2012 2:28 am |
|
|
Quote: | So, I had measured one of the 100R res (Using My Code) and the voltage was 0.30V @ 3mA, while the original HEX CODE was 1X brighter than mine, 0.6V @ 6mA. |
OK, so the old HEX CODE is still 2x as bright as your new improved code.
So, what are your measurments telling you?
My guess is your update code is still several times slower than the HEX CODE.
Assuming the code you've posted is complete and compilable I'll have a look at it later today.
Mike
EDIT
Inital results:-
I changed setup_timer_2 to give 5ms interrupt (made it easier for me to do the maths). Code now:-
Code: | setup_timer_2(T2_DIV_BY_4, 249 ,5); |
Your code
(1) Interrupts now at 5ms intervals.
(2) Takes roughly 3.5ms to update display.
(3) Your duty ratio is then ( 1.5 / 5 ) * 100% i.e. ~30% for the entire display, or 7.5% for each segment.
Your display is OFF for 70% of the time, ON for 30%
The rival HEX CODE is presumably ON for 60% of the time.
To achieve comparabilty you need to get to better than 40% OFF time.
Your update code has to be reduced to taking less than 2ms.
Your major delay is STILL in the SAME place it was previously.
I showed you a faster way before.
I'm not claiming it's the ultimate, there are far better 'C' programmers than me on this forum. I'm not a 'C' expert, there are, no doubt, some really slick ways to achieve your objective, but this goes a long way towards getting you there.
I replaced this code for one section only
Code: | //##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = (no >> (7 - i)) & 0X01 ;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
|
With this code
Code: | //##############################################################
//UPDATE DIGIT FROM ROW 0 TO 9 Speeded up version
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = no & 0X80 ;
no*=2;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
//##############################################################
|
Your code takes over 3.44ms, (the bulk of your update time).
Mine takes less than 1.36 ms. That should be enough to rival the HEX CODE.
What you're doing is shifting the variable 'no' umpteen times before testing bit zero.
What I'm doing is looking at bit seven only each time. The no*=2 shifts a new value in for the next test.
As you've done it, you will need to modify your code in four places.
Same code in four places is prime candidate for reduction to one.
Less likely to have spurious error in one version and easier to maintain.
May execute a bit slower, but as I've shown, your real problem is with the line "DATA_IN = (no >> (7 - i)) & 0X01 ; ".
You can afford a small speed penalty elsewhere.
I outlined several schemes in a previous post. The best you can do is to get the duty ratio close to 100% for the entire display (25% per segment). I'm estimating the original HEX CODE to have ~60% duty. That makes it possible to improve on the original by a factor of 100/60 or just shy of 70%. You would need a serious hardware change for that. I guesstimate SPI could achieve an update in around 100us, leaving you with ~98% duty, or well over 50% better than the HEX CODE. I'd settle for that. Anything above 90% is getting to the diminishing returns stage.
Mike |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
7 x 4 7-Segment Problem (SOLVED) |
Posted: Tue Jun 26, 2012 5:32 pm |
|
|
Hi Mike,
Your suggestion had gave me an idea to improve more the existing one and your are absolutely right that my code takes a longer time during the shifting. I made an adjustment on your code due to data flow which is i need to send the MSB first and then LSB. So the modified code as follows:
Code: |
//UPDATE DIGIT FROM ROW 0 TO 9 Speeded up version
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = no & 0X01 ;
no >>= 1;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
|
I tried it as compilation was completed and it seemed we have solved it. So right now, the display has a brightness same like the rival one but i think more improve because the new code gave more than 6.4mA compared to the rival one which is always around, 6mA.
And one more thing, how your calculate total time execution for every loop that i used...i'm curious to know it..
I got the solution now and know what to do next. Many thanks Mike for your advices, ideas, time and quick responses.
Khalis |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jun 27, 2012 2:30 am |
|
|
The way I interpreted your code, I thought you were sending MSB first, LSB last. If your modification works, good, I'm not going to argue, it's not important to me.
Now, any further improvements are going to be incremental. Each small step will be harder to achieve and produce smaller returns. What I've done is to home in on the MAJOR problem. The piece of code which executes the largest number of times will give you the largest gain. there comes a point where you have to say that's good enough and get your product into the market, or you miss the sales window.
Quote: | And one more thing, how your calculate total time execution for every loop that i used...i'm curious to know it..
|
I've had my wrists slapped before for this one, but I'll take the risk. I use MPLAB SIM. It's a free download from microchip and works with CCS or most other compilers. Remember, I don't have your hardware in front of me like you do, so can't use a 'scope / meter etc. So I need complete compilable code that I can run in the MPLAB simulator.
The inner loop from this section of code executes the largest number of times, so is a first candidate for improvement.
Code: |
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
for(i = 0 ; i <= 7 ; i++)
{
CLK_IN = 0;
DATA_IN = no & 0X01 ;
no >>= 1;
CLK_IN = 0X01;
}
}
SERIAL_EN = 0X01;
|
I replaced it with this inline code:-
Code: |
//UPDATE DIGIT FROM ROW 0 TO 9 Speeded up version 2
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++)
{
no = table[3];
CLK_IN = 0;
DATA_IN = no & 0X01 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X02 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X04 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X08 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X10 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X20 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X40 ;
CLK_IN = 0X01;
CLK_IN = 0;
DATA_IN = no & 0X80 ;
CLK_IN = 0X01;
}
SERIAL_EN = 0X01;
|
The execution time (with my compiler) reduced from 1.358ms to 644us, (another factor of 2).
The new code totally takes out the need to shift 'no', process 'i', and go round the inner loop.
I'm done now.
Mike |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Wed Jun 27, 2012 3:06 am |
|
|
So by using inline code, it would increase the speed of execution but would it may increase the size of code?Never mind, i'll explore it later. It is nice to have someone like you to en-light guy like me. Thanks a lot Mike.
Khalis |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jun 27, 2012 3:45 am |
|
|
Quote: | So by using inline code, it would increase the speed of execution but would it may increase the size of code?Never mind, i'll explore it later |
Yes of course it increases the code size, it almost invariably does.
In your case the very inner loop is extremely small, so you're taking lots of time just manipulating the loop, and not actually executing meaningful code.
It's a compromise. Speed / code size .
You pays your money and takes your choice.
The other way to explore your code is to look at the disassembly listing. It shows you what the compiler has created from your source code. One line of your code may produce anything from one to tens or more lines of assembler code.
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Jun 27, 2012 5:04 am |
|
|
As a comment:
Code: |
#define clock_bit(x) CLK_IN=0;DATA_IN=bit_test(no,x);CLK_IN=1
//UPDATE DIGIT FROM ROW 0 TO 9 Speeded up version 2.1
SERIAL_EN = 0;
for(y = 0 ; y < 10 ; y++) {
no = table[3];
clock_bit(0);
clock_bit(1);
clock_bit(2);
clock_bit(3);
clock_bit(4);
clock_bit(5);
clock_bit(6);
clock_bit(7);
}
SERIAL_EN = 0X01;
|
Saves one instruction time for each bit, and I think is a lot tidier looking.
Best Wishes |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jun 27, 2012 5:54 am |
|
|
Yes, totally agree it's a lot neater.
What I don't follow is my compiler generates the same code for both versions.
Code: | 161: CLK_IN = 0;
00BD 1288 BCF 0x8, 0x5
162: DATA_IN = no & 0X01 ;
00BE 1C2D BTFSS 0x2d, 0
00BF 1208 BCF 0x8, 0x4
00C0 182D BTFSC 0x2d, 0
00C1 1608 BSF 0x8, 0x4
163: CLK_IN = 0X01;
00C2 1688 BSF 0x8, 0x5
164:
|
and
Code: | 201: clock_bit(0);
00F8 1288 BCF 0x8, 0x5
00F9 1C2D BTFSS 0x2d, 0
00FA 1208 BCF 0x8, 0x4
00FB 182D BTFSC 0x2d, 0
00FC 1608 BSF 0x8, 0x4
00FD 1688 BSF 0x8, 0x5
202: clock_bit(1);
|
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Jun 27, 2012 7:34 am |
|
|
I get:
Code: |
.................... CLK_IN = 0;
0024: BCF 08.5
.................... DATA_IN = no & 0X01 ;
0025: MOVF 26,W
0026: ANDLW 01
0027: MOVWF 21
0028: BCF 08.4
0029: BTFSC 21.0
002A: BSF 08.4
.................... CLK_IN = 0X01;
002B: BSF 08.5
//Versus
.................... clock_bit(0);
006F: BCF 08.5
0070: BCF 08.4
0071: BTFSC 26.0
0072: BSF 08.4
0073: BSF 08.5
|
In your case it appears the compiler is optimising away the '&' operation completely. Potentially perhaps dangerous. Guessing you are using a really up to date compiler?. I've been avoiding these and sitting back in the mid 120's, because too many new problems seem to have appeared....
Best Wishes |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jun 27, 2012 2:50 pm |
|
|
Quote: | I've been avoiding these and sitting back in the mid 120's, because too many new problems seem to have appeared.... |
Just the opposite. I'm assuming you mean 4.12x, in my case it's still 3.xxx.
I've lived in Yorkshire (UK) for too long. All the locals have short arms and deep pockets.
Mike |
|
|
khalis
Joined: 12 Feb 2009 Posts: 54
|
|
Posted: Thu Jun 28, 2012 1:15 am |
|
|
Mike, I'd had tested your latest code but unfortunately, it won't run as i expected. Supposed the all bit need to be shifted to LSB so that the DATA IN pin could output it.
Ttelmah, i tested yours one and surprisingly, it increased the brightness and i measured one of 100R, it was about 8mA.
Thanks both of you. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Thu Jun 28, 2012 10:59 am |
|
|
No. Should not be a surprise.
What Ttelmah and I are telling you, is we expect to have reduced your update time to ~0.65ms. That's 13% OFF time, 87% ON time, compared to my estimate of 60% ON time for the rival HEX CODE.
You've measured 6mA current for the rival HEX CODE's estimated 60% ON time, that's roughly 0.1mA per 1%. You're now measuring 8mA for 87% ON time. For me, is near enough correct, bearing in mind the crude nature of the data we're working with.
Mike |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|