CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

7 x 4 7-Segment Problem
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Jun 24, 2012 11:39 am     Reply with quote

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.

Code:
   set_timer2(0);
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

View user's profile Send private message

PostPosted: Sun Jun 24, 2012 7:01 pm     Reply with quote

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.. Smile
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Mon Jun 25, 2012 1:40 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jun 25, 2012 5:33 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jun 26, 2012 2:28 am     Reply with quote

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

View user's profile Send private message

7 x 4 7-Segment Problem (SOLVED)
PostPosted: Tue Jun 26, 2012 5:32 pm     Reply with quote

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. Very Happy

Khalis
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 2:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 3:06 am     Reply with 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. 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

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 3:45 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 5:04 am     Reply with quote

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. Very Happy

Best Wishes
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 5:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 7:34 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jun 27, 2012 2:50 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jun 28, 2012 1:15 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jun 28, 2012 10:59 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
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