• AVR Freaks

AnsweredHot!Fastest way to access a table

Page: 12 > Showing page 1 of 2
Author
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
2019/08/24 06:31:03 (permalink)
0

Fastest way to access a table

Hi,
 
XC8 2.1 compiler , MPLAB X 5.25, PIC18F57K42


I have a table with font data, which i want to display on a graphical display.
When i write 2784 pixels in an rectangle this takes only 5,87 ms or 2.11 µs per pixel.
 
But when i fetch my data from the font table it takes 15ms to update for the same amount of pixels, this means i need 15ms to write one 46x58 pixel character. 
 
This is the function where the magic happens, looking forward to hear tips & tricks to make this lightning fast ! :)
 
const uint8_t PIXELDATA_Arial24x25[] = {0x20, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, ....

static inline void LCD_WriteColor(uint16_t color)
{
    color = ~color;
    LCD_WriteData(color >> 8);
    LCD_WriteData(color);
    
}

// here we update 1 character from a font table
for (y = 0; y < ybits; y++)
{
     for (x = 0; x < (FontEnd-1); x++)
     {
           (*glyphPtr & (1 << bitmask))? LCD_WriteColor(label->FontColor) : LCD_WriteColor(label->BackColor); // write color of pixel
           if(bitmask++==7){
           bitmask = 0;
           glyphPtr++;
          }
    }
}



glyphPtr is an uint8_t pointer to the fonttable.
 
Thank y'all !
Steve
 
#1
du00000001
Just Some Member
  • Total Posts : 3008
  • Reward points : 0
  • Joined: 2016/05/03 13:52:42
  • Location: Germany
  • Status: offline
Re: Fastest way to access a table 2019/08/24 07:19:02 (permalink)
+2 (2)
Copy *glyphPtr to a local temp variable, test for the MSBit or LSBit (whichever is appropriate) to decide upon which color to display and shift this temp accordingly.
Currently you're wasting your time shifting the maskand repeatedly accessing the pattern via the pointer  :(

PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
#2
malaugh
Super Member
  • Total Posts : 400
  • Reward points : 0
  • Joined: 2011/03/31 14:04:42
  • Location: San Diego
  • Status: offline
Re: Fastest way to access a table 2019/08/24 08:00:44 (permalink)
+2 (2)
One area that is slowing the function down is the (1 << bitmask) statement. As bitmask increase, so does the number of shifts. I would change this by storing *glyphptr in a variable and shifting that once every time through the loop.
#3
Gort2015
Klaatu Barada Nikto
  • Total Posts : 3233
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/24 09:54:36 (permalink)
0
Are you writing each individual pixel?
 
ie. Rectangle of 100 x 50
 
If you are then that requires 5000 writes even if you are writing to a buffer.  Animations will not be possible.
 
You can increase the speed in 6 ways.
1. Fast masking techniques, don't write bits, write 16bit words.
2. A Bit array representing the refresh state of each bit.
   (Why refresh the whole lcd when only 50 pixels changed)
3. Time based refreshes.
4. Wider cpu bus.
5. Adjust timings.
6. My favorite - the driver resides on the 2nd core (dual core CPU)
 
I have a flood fill function that runs so fast that you would think it was a Ryzen 3900x.
 
 
 
post edited by Gort2015 - 2019/08/24 10:08:29

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#4
Gort2015
Klaatu Barada Nikto
  • Total Posts : 3233
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/24 10:06:40 (permalink)
0
Fonts are the same as any bitmap.
They have to be masked into the correct x position and also the width has to be masked.
If you do not mask you will not get fast smooth drawing.
 
It is not as simple as it appears.
(x and width can cross 16bit word boundry)
 
If you modify the display the background must be preserved.
post edited by Gort2015 - 2019/08/25 02:38:50

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#5
du00000001
Just Some Member
  • Total Posts : 3008
  • Reward points : 0
  • Joined: 2016/05/03 13:52:42
  • Location: Germany
  • Status: offline
Re: Fastest way to access a table 2019/08/24 10:31:51 (permalink) ☼ Best Answerby picmaster75 2019/08/26 01:14:25
+1 (1)
What I missed on the first look:
what's that nonsense about inverting the color value for each pixel? !
Using the targeted value right away from the start is just - - - faster.

PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
#6
simong123
Lab Member No. 003
  • Total Posts : 1310
  • Reward points : 0
  • Joined: 2012/02/07 18:21:03
  • Location: Future Gadget Lab (UK Branch)
  • Status: offline
Re: Fastest way to access a table 2019/08/24 18:52:27 (permalink) ☄ Helpfulby picmaster75 2019/08/26 01:20:01
+2 (2)
The following is simplified from a graphics library I am currently writing, somewhat modified to your names where they are obvious. This assumes the MSB is the pixel in the glyph corresponding to smallest x.
    uint8_t fgh=~(label->FontColor>>8);
    uint8_t fgl=~(label->FontColor);
    uint8_t bgh=~(label->BackColor>>8);
    uint8_t bgl=~(label->BackColor);
    
    uint8_t cl=(*glyphPtr++);
    
    for (y = 0; y < (FontHeightInPixels); y++)
    {
        for (x = 0; x < (FontWidthInPixels); )
        {
            if (cl&0x80)
            {
                LCD_WriteData(fgh);
                LCD_WriteData(fgl);
            }
            else
            {
                LCD_WriteData(bgh);
                LCD_WriteData(bgl);
            }

            x++;
            cl=(x&0x07)?cl<<1:*glyphPtr++;
        }
    }

I would personally also make LCD_WriteData() a macro, or explicitly inlined function.

Also, what du00000001 said about the colour variables. Why the inverse?
#7
1and0
Access is Denied
  • Total Posts : 9623
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Fastest way to access a table 2019/08/24 21:18:09 (permalink)
+1 (1)
What values are 'ybits' and 'FontEnd'?  A do-while() loop with pre-decrement condition is faster than a for() loop.
 
#8
Gort2015
Klaatu Barada Nikto
  • Total Posts : 3233
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/25 02:55:19 (permalink)
-2 (4)
Writing individual pixels?  I can't believe that is even on the table.
 
Your fired.

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#9
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:18:24 (permalink)
0
@du00000001
correct, that was one of the techniques i have tried, though this change only save few ms at updating the whole screen.
I can't believe why this color need to be inverted in the first place, the ST7789V controller use 5R6G5B color (16 bit), but for some reason these bytes are inverted.
 
#10
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:21:14 (permalink)
0
simong123
The following is simplified from a graphics library I am currently writing, somewhat modified to your names where they are obvious. This assumes the MSB is the pixel in the glyph corresponding to smallest x.
    uint8_t fgh=~(label->FontColor>>8);
    uint8_t fgl=~(label->FontColor);
    uint8_t bgh=~(label->BackColor>>8);
    uint8_t bgl=~(label->BackColor);
    
    uint8_t cl=(*glyphPtr++);
    
    for (y = 0; y < (FontHeightInPixels); y++)
    {
        for (x = 0; x < (FontWidthInPixels); )
        {
            if (cl&0x80)
            {
                LCD_WriteData(fgh);
                LCD_WriteData(fgl);
            }
            else
            {
                LCD_WriteData(bgh);
                LCD_WriteData(bgl);
            }

            x++;
            cl=(x&0x07)?cl<<1:*glyphPtr++;
        }
    }

I would personally also make LCD_WriteData() a macro, or explicitly inlined function.

Also, what du00000001 said about the colour variables. Why the inverse?


thank you for this example , i will try and let you know the results

LCD_WriteData is already declared as inline function.
#11
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:24:46 (permalink)
0
Gort2015
Writing individual pixels?  I can't believe that is even on the table.
 
Your fired.


Its easy too tear down people, but please tell me any other way to send 16 bit color data to the ST7789V controller if you know better
#12
du00000001
Just Some Member
  • Total Posts : 3008
  • Reward points : 0
  • Joined: 2016/05/03 13:52:42
  • Location: Germany
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:27:52 (permalink)
+1 (1)
@ picmaster..
How many ("few") ms do my suggestions save?
Considering the 6 ms for rectangle drawing, you shouldn't expect to be faster than that.
PLUS: how is the LCD attached? You didn't yet show the code for LCD_WriteDate()

PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
#13
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:27:58 (permalink)
0
Gort2015
Are you writing each individual pixel?
 
ie. Rectangle of 100 x 50
 
If you are then that requires 5000 writes even if you are writing to a buffer.  Animations will not be possible.
 
You can increase the speed in 6 ways.
1. Fast masking techniques, don't write bits, write 16bit words.
2. A Bit array representing the refresh state of each bit.
   (Why refresh the whole lcd when only 50 pixels changed)
3. Time based refreshes.
4. Wider cpu bus.
5. Adjust timings.
6. My favorite - the driver resides on the 2nd core (dual core CPU)
 
I have a flood fill function that runs so fast that you would think it was a Ryzen 3900x.
 
 
 


You are using whole different contollers for these kind of techniques. What you say is not possible with the ST7789V controller, exept for wider CPU bus.
#14
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:30:39 (permalink)
0
du00000001
@ picmaster..
How many ("few") ms do my suggestions save?
Considering the 6 ms for rectangle drawing, you shouldn't expect to be faster than that.
PLUS: how is the LCD attached? You didn't yet show the code for LCD_WriteDate()


The whole display takes 140ms to update (without reading fonts, just writing 1 color), take away the color invertion saves 6ms .
 
static inline void LCD_WriteData(uint8_t data)
{
    LCD_WRX_PIN_SetLow();
    LCD_8BIT_PINS_SetData(data);
    LCD_WRX_PIN_SetHigh();
}
#15
du00000001
Just Some Member
  • Total Posts : 3008
  • Reward points : 0
  • Joined: 2016/05/03 13:52:42
  • Location: Germany
  • Status: offline
Re: Fastest way to access a table 2019/08/26 01:41:19 (permalink)
+2 (2)
Looks like any one or two instruction(s) spared account(s) for 6 ms when redrawing the whole screen.
Continue with removing this inline scrap - using macros instead.
Redrawing only what's required to be redrawn would further speed-up the updates - at the cost of more sophisticated output control routines.
 
Might be interesting to see the code for the "innards" of LCD_WriteData()

PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
#16
1and0
Access is Denied
  • Total Posts : 9623
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Fastest way to access a table 2019/08/26 02:00:03 (permalink)
+1 (1)
This
color = ~color;

takes 6 ms.  Wow, you can save a lot more then.
 
<edit> The fastest way would be assembly. ;)
post edited by 1and0 - 2019/08/26 02:02:40
#17
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 02:51:11 (permalink)
0
du00000001
Looks like any one or two instruction(s) spared account(s) for 6 ms when redrawing the whole screen.
Continue with removing this inline scrap - using macros instead.
Redrawing only what's required to be redrawn would further speed-up the updates - at the cost of more sophisticated output control routines.
 
Might be interesting to see the code for the "innards" of LCD_WriteData()


the standard mcc stuff .... i did try without do{} while loop, that makes no difference.
#define LCD_WRX_PIN_SetLow()             do { LATCbits.LATC0 = 0; } while(0)
 
wondering if DMA can do anything to make this faster, that would take some experimenting :)
#18
picmaster75
New Member
  • Total Posts : 20
  • Reward points : 0
  • Joined: 2018/09/21 03:45:11
  • Location: 0
  • Status: offline
Re: Fastest way to access a table 2019/08/26 02:55:00 (permalink)
0
1and0
This
color = ~color;

takes 6 ms.  Wow, you can save a lot more then.
 
<edit> The fastest way would be assembly. ;)


 yes , for 76800 pixels, so this means inverting takes 78ns per pixel, thus 1 instruction @ 64Mhz (with exact timing measurement , i would see a profit of 4.8 ms)
 
The byte fetching from table and bittesting are the culprits. 
#19
1and0
Access is Denied
  • Total Posts : 9623
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Fastest way to access a table 2019/08/26 03:09:11 (permalink) ☄ Helpfulby picmaster75 2019/08/27 12:37:25
+2 (2)
color = ~color;  takes at least 2 instructions.
 
*glyphPtr requires setting up TBLPTR, TBLRD, and read TABLAT; so copy it to a temp variable as suggested will save a lot of instructions.
 
Replace for() loops with do-while(--x) loops as I've suggested will save some cycles too.
 
Get rid of the bitmask too. <edit> Instead, test a fixed bit. </edit>
 
 
post edited by 1and0 - 2019/08/26 03:13:32
#20
Page: 12 > Showing page 1 of 2
Jump to:
© 2019 APG vNext Commercial Version 4.5