Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Erasing 32k eeprom with loading bar, cpu load high

Status
Not open for further replies.

smitchel

New Member
Hi everyone,

I'm working on a function that erases every single byte on eeprom 24LC256 and displays the progression on an lcd screen. My code works fine, but I feel like I'm missing something. I use ISIS to simulate my circuit and the cpu load rises up to 85%. I have a Core i7 and it makes wonder if on the real microcontroller (pic 16f877) it won't be a lot.
I wanted to display a loading bar on the lcd screen so I was able to see the progression in percent. Before adding the loading bar, the process of erasing the eeprom took about 5 minutes, and now it takes 7. So I'd like your opinions on my code and let me know if there was something I could do better.
The function fc_i2c_write(); is just a function I made wich receives the high and low address with the byte to write and uses i2c to write it on the eeprom.
I've had problems with my loops, so I had to set my addrH variable to 0xFF so when it starts the loop and add 1 it will actually starts with the 0x00 address.
Also, I have to use my function twice in my loop, once in my first loop from 0 to 127 to include all the 0x00 low addresses of any high address and a second time in the second loop to include all the other addresses. Same thing here, I feel like I could simplify the code, but I'm not sure how.

For my loading bar, I use the progression variable and add 1 everytime a loop is done. Since I know that there are 32768 bytes, I use a simple division to get the percentage.
With 16 caracters on a single line on the lcd screen I divided 100/16 which gave me 6.25. I then compare my percentage to see if it has reached the treshold of 6.25, if it is the case then I add 6.25 to my new treshold and put a bar on the screen. I'm not sure if that how loading bars should be done though.

There's a lot of conditions and given the number of times the loop is done, it's high on the cpu load, I really would like to reduce my code if it is possible.

You'll find below my code and a screenshot of the result, which displays the address of the eeprom first, then the byte number and then the percentage. Below you can see the loading bar.

Thank you in advance for you help.

View attachment 64606

Code:
short int fc_i2c_erase_all()
{
      short int addrH, addrL, n;
      float p;
      float s;
      unsigned int progression;
      char affiche[10], affiche2[10], affiche3[10], affiche5[10], ii[10];
      int i, j;
      //char affiche[10];
      //char affiche2[10];
      char affiche4[] = "0";
      Lcd_Cmd(_LCD_CURSOR_OFF);
      addrH = 0xFF;                                     
      progression = 0;
      s = 6.25;
      for (i = 0; i <= 127; i++) {                       
           addrH = addrH + 1;                          
           //IntToStr(i, ii);
           //Lcd_Out(2,1,ii);                                            
           addrL = 0x00;                                
           ShortToHex(addrH, affiche);
           Lcd_Out(1,1,affiche);

           fc_i2c_write(addrH, addrL, 0x00);          
               ShortToHex(addrL, affiche2);
               Lcd_Out(1,3,affiche2);
               //Delay_ms(500);
               progression = progression + 1;
           for (j = 0; j < 255; j++) {                  
               addrL = addrL + 1;
               ShortToHex(addrL, affiche2);
               Lcd_Out(1,3,affiche2);
               fc_i2c_write(addrH, addrL, 0x00);     
               progression = progression + 1;
               p = progression*100.0/32768.0;
               //p = p/32768.0;
              
               IntToStr(progression, affiche3);
               Lcd_Out(1,5,affiche3);
               
               
               IntToStr(p, affiche5);
               Lcd_Out(1,10,affiche5);
               }
               //if (progression*100.0/32768.0 >= s)
               if (p >= s)
                  {
                    s = s + 6.25;
                    for (n = 1; n < s/6.25; n++) {
                    //Lcd_Out(2,n,affiche4);
                    Lcd_Chr(2, n, 0xFF);
                    }
                  }
      }
}
 
Last edited:
Why is cpu load a problem?, generally a PIC wouldn't be doing anything else at the same time so it doesn't matter - but most of your load is probably because you're using floating point maths? (which there seems no need for).
 
So I use float points because my numbers have numbers after the . like my 6.25 threshold. And as I mentioned earlier, it takes two more minutes to erase the eeprom which is why I was wondering if I could simplify something.
As for the 7 minutes, I can't get below 5. It takes 5 ms to write the eeprom, and that's from the data sheet. Even with a page wryte wich can only go up to 64 bytes, I still have to wait before sending another instruction. But if you think you it only takes a few seconds then I'd like to see a working code.
 
So I use float points because my numbers have numbers after the . like my 6.25 threshold. And as I mentioned earlier, it takes two more minutes to erase the eeprom which is why I was wondering if I could simplify something.
As for the 7 minutes, I can't get below 5. It takes 5 ms to write the eeprom, and that's from the data sheet. Even with a page wryte wich can only go up to 64 bytes, I still have to wait before sending another instruction. But if you think you it only takes a few seconds then I'd like to see a working code.

I think a 'few seconds' was perhaps a bit of an exaggeration?.

But if a page write of 64 bytes takes 5mS, then it's only 512x5mS to write it all.
 
Well I thought about that but you still have to take into consideration the time the pic takes to address all the bytes, to address 512 times 64 bytes, you need to make to loops one that counts to 512 and another inside that counts 64 times, which is about the same thing as what I've already done, except I save 512 times 5ms.
 
Well I thought about that but you still have to take into consideration the time the pic takes to address all the bytes, to address 512 times 64 bytes, you need to make to loops one that counts to 512 and another inside that counts 64 times, which is about the same thing as what I've already done, except I save 512 times 5ms.

Loops take almost no time at all, are you perhaps doing un-needed maths during the loops?.
 
well I don't know, I posted the code if you want to take a look a it and tell me. But every time I have a condition to see wether I've reached a treshold for my loading bar.
 
Are the first two parameters for your Lcd_Out() function <line> and <tab>?

Is your progress bar 16 characters wide with each character representing 2048 bytes of the total 32768 bytes?

Are you writing a 4 digit hexadecimal address, a 5 digit decimal address, and a 2 digit percentage on the LCD screen for every one of the 32768 bytes erased (360448 characters total)?
 
Last edited:
well I don't know, I posted the code if you want to take a look a it and tell me. But every time I have a condition to see wether I've reached a treshold for my loading bar.

Why would you want to do it like that? - the loading bar is a fixed 16 characters. So simply have an outer loop of 16 (which updates the display every loop, and calls a 'mid-level' loop), and an inner loop of 64 times which loads the EEPROM and writes that block.

No calculations required at all.
 
That's what I was thinking too... But is he erasing individual bytes or 64 byte pages?

Code:
void fc_i2c_erase_all()
{ char i, j; int progression = 0;           //
  for(i = 0; i < 16; i++)		    //
  { for(j = 0, j < 2048, j++)               //
    { addrH = progression / 256;            //
      addrL = progression % 256;            //
      Lcd_Out(1,1,ShortToHex(addrH));	    // hex address hi
      Lcd_Out(1,3,ShortToHex(addrL));	    // hex address lo
      Lcd_Out(1,5,IntToStr(progression));   // decimal address
      Lcd_Out(1,10,IntToStr(progression/327));  // percentage
      fc_i2c_write(addrH, addrL, 0x00);	    //
      progression++;			    //
    }					    //
    Lcd_Out(2,i,"0");		            // bargraph char
  }					    //
}
 
Last edited:
So the first two parameters for the Lcd_Out() function are indeed the line and tab. But the a character in my progress bar doesn't represent 2048bytes. One character, which appears as one bar, reprents 6.25% of the progression. 6.25% of 32768bytes total. All the other digits are the hexadecimal address, decimal address and the percentage like you said. But it was just for debbuging purposes, I wanted to make sure that the addresses were right, that the counter (the 5 digit decimal) was counting to 32768 and the percentage which I need for my loading bar.
In the end, the maths I did is, (my counter*32768/100 = it gets me the percentage) then I said that everytime that my percentage was superior to my variable s (which equals 6.25 when the program start's) I'll add 6.25 to that variable, and for my new s variable divided by 6.25 (s/6.25) I'll have a loop where I'll display a bar on the each column, knowing that it can never exceed 100 since the counter stops at 32768.
 
So the first two parameters for the Lcd_Out() function are indeed the line and tab. But the a character in my progress bar doesn't represent 2048bytes. One character, which appears as one bar, reprents 6.25% of the progression. 6.25% of 32768bytes total. All the other digits are the hexadecimal address, decimal address and the percentage like you said. But it was just for debbuging purposes, I wanted to make sure that the addresses were right, that the counter (the 5 digit decimal) was counting to 32768 and the percentage which I need for my loading bar.
In the end, the maths I did is, (my counter*32768/100 = it gets me the percentage) then I said that everytime that my percentage was superior to my variable s (which equals 6.25 when the program start's) I'll add 6.25 to that variable, and for my new s variable divided by 6.25 (s/6.25) I'll have a loop where I'll display a bar on the each column, knowing that it can never exceed 100 since the counter stops at 32768.

Sorry, but this is another example of why I think people should learn assembler rather than jumping straight to a high level langauge, you're making it all FAR more complicated than it needs to be.

You've got 16 steps, so it's 16th's - simply use an extra outer loop, nothing to check or calculate.

The fact it's all binary (32K addressing) means it's all nice simple whole numbers.

You're going about it in a difficult and complicated fashion - why on earth are you even mentioning percentages?.
 
Well I really don't know, at first I just wanted to erase all my bytes with two loops to get all my addresses, it's only then that I decided to add a loading bar, I didn't know how to do it, so I figured out a way to do it. As for the percentage, it just made sense to have a loading bar with the percentage. But again, like I said I wanted to simplify my code, I know it wasn't too good, though it worked.

Thanks Mike though, you did the simplification I wanted. It's much clearer than my code, and lighter on the cpu.
 
You're welcome. Glad we could help.

The LCD routines may include 50 usecs or more delay between LCD write operations so you should see a significant improvement once you remove the LCD commands you're using to debug your code. Erasing 64 byte "pages" instead of individual bytes should also improve speed.

Have you considered using custom characters for a bar graph of eighty vertical lines?

Cheerful regards, Mike
 
Last edited:
So, I tried the code, and unfortunately it doesn't work right. The solved the first problems, which were because you changed parameters of some functions, the ShortToHex() or IntToStr() needs two parameters and doesn't return any value, so they can't be put in the Lcd_Out() function.
There are other problems though. The most obvious is that the loading bar doesn't work. it doesn't display anything on the second line of the lcd screen. I changed the value "0" which you put and tried mine, which worked before 0xFF for a black character, but in vain.
And the last one, when the counter reaches 100%, then progression counts back, the hex address exceeds 7FFF which should be the last one and the percentage gets a minus sign.

Also I noticed you re-edit your post and changed your code, maybe the previous version would work better.
One last thing, it takes now a little bit more than 8 minutes to erase the eeprom.

As for the using custom characters for a bar graph of eighty vertical lines, I have actually considered it, but I couldn't figure out how to do it, because then I'd have to have five different custom characters, one for each new column on the same column and I just thought that the code would become really messy, mine being what it was already.

Here's the code I compiled.

oh I almost forgot, this code, could only work with a byte write mode (one byte at a tome for a given address) , not a page write (64bytes) because the addresses should be calculated differently, that's also something I wasn't too sure how to do it, since you need to count by range of 64bytes, but the fact that there are two bytes of addresses makes more complicated, if you are at the end of the low address, you need to add one to the high address, and keep counting the low address while making sure not to exceed the 7FFF address.


Code:
{ char i, j; int progression = 0;
       short int addrH, addrL;
       char affiche[10], affiche2[10], affiche3[10], affiche4[10];
       for (i = 0; i < 16; i++)		    //
       { for (j = 0; j < 2048; j++)               //
        { addrH = progression / 256;            //
          addrL = progression % 256;            //
          ShortToHex(addrH, affiche);
          Lcd_Out(1,1,affiche);      	    // hex address hi
          ShortToHex(addrL, affiche2);
          Lcd_Out(1,3,affiche2);	    // hex address lo
          IntToStr(progression, affiche3);
          Lcd_Out(1,5,affiche3);   // decimal address
          IntToStr(progression/327,affiche4);
          Lcd_Out(1,10,affiche4);  // percentage
          fc_i2c_write(addrH, addrL, 0x00);	    //
          progression++;			    //
        }					    //
        Lcd_Out(2,i,0xFF);		            // bargraph char
  }					    //
}
 
Last edited:
Well I found a partial solution, the command I used iniatially to display my loading bar was Lcd_Chr(2, i, 0xFF); but I didn't pay attention to that and you used the Lcd_Out() function, also, since the i started with the 0 value, nothing would appear the first time, and it could only go up to 15 so not full address. So now I make it start with a value of 1 "for (i = 1; i <= 16; i++)"
 
I figured out where the problem came from, the j variable was declared as a char which is has a 8-bit size, I declared it as an int and which has a 16-bit size and now it works and stops at 7FFF.
I'd still like to see your previous code, if you can post.
Thank you again for you code, you helped me a lot here. I don't understand why it takes longer though, but it's much clearer now, and without the debugging displays I'm sure it'll get faster.
I'm curious for the custum loading bar using 80 vertical lines though, if you have any way to do it, let me know.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top