Spark Logic

Port manipulation – LCD 8bit parallel

wizarcl Thu Aug 06, 2015 11:51 pm

Hi everyone.
I’m trying to port Adafruit_TFTLCD library (for 8bit parallel LCD) and inside in library, control lines is controlled by macros, using port manipulation, but STM32 has a different method to make this. Using AVR, library make control using DDRA and PORTA, for example, to control port direction and values. How can I make this manipulations? Using GPIOA_BASE.CRL, GPIOA_BASE.CRH, GPIOA_BASE.IDR and GPIOA_BASE.ODR?

Follow a piece of code in pin_magic.h:

#define write8inline(d) { \
PORTD = (PORTD & B00000011) | ((d) & B11111100); \
PORTB = (PORTB & B11111100) | ((d) & B00000011); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
DELAY7; \
result = (PIND & B11111100) | (PINB & B00000011); \
RD_IDLE; }
#define setWriteDirInline() { DDRD |= B11111100; DDRB |= B00000011; }
#define setReadDirInline() { DDRD &= ~B11111100; DDRB &= ~B00000011; }

Replies

RogerClark Sun Jul 03, 2016 10:27 pm

Interesting.

I looked at some previous postings to the forum e.g. http://www.stm32duino.com/viewtopic.php?t=862&start=40

and it looks like operations which set individual pixels are faster, but anything that fills large areas are slower.

From what I recall the adafruit SPI based library is not very effecient at writing individual pixels, and I suspect that improvements could be made to the SPI version which may improve single pixel access speed in the SPI version.
(I think the Teensy has an optimised library with fast pixel access)

Where this really comes into its own, is on boards that use the F103V or F103Z, which have whole GPIO ports that are unused.
And further speed improvements can be gained where there are separate data and address ports.

RogerClark Sun Jul 03, 2016 11:02 pm

Just a quick followup about slow single pixel write speeds in the SPI version, and unless i have looked in the wrong file…

the drawpixel function wastes a lot of time, as it assumes its being called for a one off command, but as its called from the functions which draw triangles etc, it makes operations like triangles slow.

The simple solution, is to have 2 functions to write a pixel, one that works standalone and one that needs the SPI to be initialised for it e.g Chip Select pins etc to be toggled.
then get the triangle functions to call the non-standalone version.

Ideally the non-standalone function would be private to the class, but because the Text generator is in a separate cpp, I think to optimise the text, the new function would need to be made public, which is not ideal, but not something I would loose sleep over ;-)

void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) {

if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return;

if (hwSPI) spi_begin();
setAddrWindow(x, y, x + 1, y + 1);

*dcport |= dcpinmask;
*csport &= ~cspinmask;

spiwrite(color >> 8);
spiwrite(color);

*csport |= cspinmask;
if (hwSPI) spi_end();
}

iwalpola Sun Jul 03, 2016 11:13 pm

@ Roger, you’re almost right, and you’re referring the SPI code, not the 8 bit parallel. The triangle drawing functions call the functions which draw lines (horizontal, vertical or inclined). These functions in turn call the draw pixel function, but only if length of line is 1px.

However, on the line drawing, screen filling etc, where there is a lot of data to be written, there was room for improvement in CHIP_SELECT toggling and toggling of RS pin (which decides whether data written is command or data).

So after adjusting (after doing a git diff), the benchmark is better than Kurt’s mod!! Maybe there is room for even more improvement, but I guess this is pretty good.

Benchmark Time (microseconds)
Screen fill 784951
Text 27277
Lines 242789
Horiz/Vert Lines 66034
Rectangles (outline) 42204
Rectangles (filled) 1630078
Circles (filled) 240487
Circles (outline) 180967
Triangles (outline) 58242
Triangles (filled) 563808
Rounded rects (outline) 84634
Rounded rects (filled) 1777583

RogerClark Sun Jul 03, 2016 11:25 pm

Yes. I was referring to the SPI version

Does the parallel version toggle CS etc for every pixel, or did you optimise it?

iwalpola Sun Jul 03, 2016 11:39 pm

RogerClark wrote:Yes. I was referring to the SPI version

Does the parallel version toggle CS etc for every pixel, or did you optimise it?

RogerClark Mon Jul 04, 2016 12:43 am

iwalpola wrote:
It was doing CS toggle for every pixel write earlier (my dumb idea). Now I fixed it.

I was worried that it will interfere with the touch digitizer output available in the same module (TFT and Touch share 4 pins).

martinayotte Mon Jul 04, 2016 2:09 am

I start to misunderstanding the whole thread here :
On every parallel 8bis transfer, there must be an CS pulse.
So, how can that be skipped for optimisation ?

RogerClark Mon Jul 04, 2016 2:17 am

CS can probably me skipped if only one device is on SPI, but its hard coded into the Adafruit Ili9341 lib.

The other line that has to be toggled a lot is the Data / command pin

It looks like the main reason that writing single pixels is slow is not the CS line but the unnecessary calling of SPI begin transaction before writing each pixel, which takes up a huge amount of time, as the whole SPI device has to be disabled and all settings updated etc etc etc

Some minimal changes would result in a massive speed improvement in some functions e.g. drawing of diagonal lines , but the Adafruit graphics lib would need to also be updated to yield faster text speeds.

If I get time this evening, I will take a quick look at the existing code in the Adafruit_ili9341_STM lib (for F1)

iwalpola Mon Jul 04, 2016 2:36 am

Yet another performance gain by inlining the write8special() function.
Demo (almost too fast to see):
https://youtu.be/sGU_wwX20hM

@Roger, there must surely be potential for improvement in the SPI code as well. What I learned today is that even microseconds worth of delay adds up fast when you repeat it 10000’s of times.

Benchmark Time (microseconds)
Screen fill 320577
Text 14869
Lines 129592
Horiz/Vert Lines 25437
Rectangles (outline) 16493
Rectangles (filled) 666012
Circles (filled) 104502
Circles (outline) 96406
Triangles (outline) 30358
Triangles (filled) 230338
Rounded rects (outline) 41103
Rounded rects (filled) 709046
Done!

RogerClark Mon Jul 04, 2016 4:03 am

Thanks for posting an updated video

Re: SPI version

Yes.
Now I look at the code, there is loads of room for improvement, and like you said, even a few uS shaved off here and there in the low level functions make a big difference.

What is still slower for you is the fill stuff as you can’t benefit from DMA. Well, if the pins were adjacent from the beginning of a port you could use DMA as you can DMA to GPIO (but we don’t have any demo code for this)
But as you use pins all over the board, DMA will not really help :-(

ahull Mon Jul 04, 2016 10:03 am

iwalpola wrote:Yet another performance gain by inlining the write8special() function.
Demo (almost too fast to see):
https://youtu.be/sGU_wwX20hM

@Roger, there must surely be potential for improvement in the SPI code as well. What I learned today is that even microseconds worth of delay adds up fast when you repeat it 10000’s of times.

Benchmark Time (microseconds)
Screen fill 320577
Text 14869
Lines 129592
Horiz/Vert Lines 25437
Rectangles (outline) 16493
Rectangles (filled) 666012
Circles (filled) 104502
Circles (outline) 96406
Triangles (outline) 30358
Triangles (filled) 230338
Rounded rects (outline) 41103
Rounded rects (filled) 709046
Done!

racemaniac Mon Jul 04, 2016 1:54 pm

RogerClark wrote:Thanks for posting an updated video

Re: SPI version

Yes.
Now I look at the code, there is loads of room for improvement, and like you said, even a few uS shaved off here and there in the low level functions make a big difference.

What is still slower for you is the fill stuff as you can’t benefit from DMA. Well, if the pins were adjacent from the beginning of a port you could use DMA as you can DMA to GPIO (but we don’t have any demo code for this)

RogerClark Mon Jul 04, 2016 9:28 pm

Thanks

RogerClark Mon Jul 04, 2016 10:38 pm

@iwalpola

Can you post the code to your sketch that you use for those timing results, as I don’t think its the same sketch that I am using to compare SPI speeds

(Or post a link to the sketch source code)

Thanks

Roger

iwalpola Tue Jul 05, 2016 9:12 pm

RogerClark wrote:post code

ahull Tue Jul 05, 2016 10:03 pm

Benchmark Time (microseconds)
Screen fill 320577
...

RogerClark Tue Jul 05, 2016 10:27 pm

SPI is currently giving me these results

Benchmark Time (microseconds)
Screen fill 170787
Text 22869
Lines 241990
Horiz/Vert Lines 15802
Rectangles (outline) 11547
Rectangles (filled) 355060
Circles (filled) 142830
Circles (outline) 173697
Triangles (outline) 59139
Triangles (filled) 165883
Rounded rects (outline) 59967
Rounded rects (filled) 415460

ahull Tue Jul 05, 2016 10:32 pm

Its interesting to note that not everything is improved with DMA, line drawing and text for example appears to be slower.
Do we know what the absolute limits of the display are, in terms of speed?

iwalpola Wed Jul 06, 2016 6:18 am

ahull wrote:Roughly how many parallel writes per second do you think you are able to manage?

Sign in to reply