How do I send part of an ArrayBuffer to SPI #7620
Replies: 1 comment
-
Posted at 2020-08-28 by @MaBecker hi, if you can build your own firmware you might include this https://github.com/espruino/Espruino/blob/master/libs/graphics/lcd_spi_unbuf.c Posted at 2020-08-29 by jeffmer Thanks, that is really neat. I will try to compare the performance with my driver which uses drawImage. I suspect the performance of drawImage implemented on top of single pixel operations will not be great. I still think it would be generally useful to be able to write parts of flat buffers to SPI . Posted at 2020-08-29 by @MaBecker
Well it's using Posted at 2020-08-29 by jeffmer That's very impressive. I have just managed to build ESP32 firmware including it using your excellent tutorial. I think spi_lcd_unbuf should be added to the standard ESP32 board as most people will want to have a display. Posted at 2020-08-29 by @MaBecker Well Gordon was so generous and let me add this library and also did a refactoring/rewording of the tutorials. So don't miss to donate and help to improve the ESP32 build Posted at 2020-08-29 by jeffmer This caused me a little grief with your custom board tutorial:
Should be LCD_SPI_UNBUF! Posted at 2020-08-29 by @MaBecker Hmm, yes has to be changed, thanks for naming. Edit: Just created a pr Posted at 2020-08-29 by jeffmer Hi, I have now managed to do a comparison. See video below: The numbers in red are the
The You can see the full code here Posted at 2020-08-29 by @MaBecker Thanks for sharing. Yep, of cause drawImage() is always faster than drawString() with vector font. Video post #4 is using setFont("6x8",4) because it is much faster than using vector and with option true no clear is needed, so this is similar to drawImage().
My conclusion:
Posted at 2020-08-29 by @MaBecker Hmm, not sure any more. Tested a lcd spi ILI9341 with 320x240 pixel, interval 0.1sec and it's not as slow as in video post #9.
Posted at 2020-08-30 by @fanoush
Can't easily verify the spi.write since it does not return anyting but with spi.send it works as expected at least for nrf52. See this
so it can be seen only two bytes are sent in second case. Maybe don't use Posted at 2020-08-30 by jeffmer Thanks, I did try that and I think you are correct in that now that I have redone the experiment it does seem to send the right amount of data. However, it seems to scramble the pixel data in some way that I have not yet worked out:-( Will investigate further (tbc) ........ Posted at 2020-08-30 by jeffmer Finally got it to work - perhaps obvious in retrospect!
Posted at 2020-08-31 by @MaBecker Hey, thanks for your update, look's like a great improvement for flicker free vector font drawing. So why not add Posted at 2020-08-31 by jeffmer I think that’s a great idea and I will certainly have a go at it when time permits. Posted at 2020-08-31 by @gfwilliams
I probably wouldn't want to merge something in if it was a specific hack for There are some really easy wins for
Posted at 2020-08-31 by jeffmer Having looked at the Espruino graphics C code, I can see that there is no provision for an image bit blit style callback as there is for pixels and rectangles, so I completely agree that it’s best left as it is. I am impressed that Espruino supports reasonable performance for drawImage using only Javascript. Posted at 2020-08-31 by @MaBecker
Thanks, so let me run some tests and come up with a pr. Posted at 2020-09-01 by @MaBecker
Any things else you like to point out to improve performance? Posted at 2020-09-01 by @gfwilliams That's the main one and you should see some decent speed improvements with that. The other one would be to move to DMA. If you reserved 2 LCD_WIDTH length buffers then you could:
I believe this is the sort of thing @fanoush already tried when he ported to some watches with SPI displays - you can effectively be doing the transmission at the same time as working out the next stuff to draw. Posted at 2020-09-01 by @fanoush Yes, but it can be done because my driver does two things (in parallel) when updating some rectangular area
If you keep those steps separated - palette conversion done via E.mapInPlace or drawImage into buffer and then using lcd_spi_unbuf driver for sending the area over SPI, you cannot do it in parallel So it comes back to
and
This is specific optimization for DMA based (in this case SPI) graphics driver - draw image in any bpp/palette source into destination rectangle in different bit depth (mainly RGB). So adding this to the unbuffered driver makes sense to me. @gfwilliams what version of such code would you merge? if it should reuse some generic palette/bpp conversion graphics code it would need to be callable in chunks - i.e. 'convert next x bytes from source into this buffer'. Or is there some other way to look at it? Maybe it could be somehow hooked into drawing algorithms directly and be somehow line based? Thats not what I did, it first needs to be drawn into memory buffer completely and then conversion/blitting is done in g.flip for modified rectangle. With this unbuffered driver it would be the same just without full buffer for whole screen but only for smaller rectangular image so g.flip() would become g.drawImage(). @jeffmer not sure if you've seen it, the InlineC method of my driver (version for DK08 watch, the destination is 6bit RGB) is here and calling it in g.flip is here For P8 watch and 240x240 ST7789 destination is 12 bits RGB (saves 33% vs 16 bit RGB). 12bit mode is also on ST7735 but maybe it is not so visible on smaller screens, with 240x240 the 33% speedup is visible. Posted at 2020-09-01 by @gfwilliams There are some very specific hacks for Bangle.js graphics: https://github.com/espruino/Espruino/blob/master/libs/graphics/lcd_st7789_8bit.h#L52 But I'd rather not have IFDEFs piled up on top of each other. I guess what we need is to have a more generic way of adding optimisations. If you want to do optimisation on the Graphics library it'd be great - but ideally try and optimise it such that it benefits everyone, not just one specific use case that you have to compile custom firmware for. Posted at 2020-09-01 by jeffmer I updated my copy of @fanoush - yes, I had a look before - it’s really neat. Posted at 2020-09-01 by @MaBecker
just created pr 1924 for this. Posted at 2020-09-02 by @MaBecker This optimization is perfect for drawing horizontal lines Display 240x240(320) before: 990ms, after 266ms
I guess it should be possible to optimize this for vertical line too? Posted at 2020-09-02 by @fanoush yes, if you set x,y to start and then width to 1 and height to line length each new pixel should 'overflow' to next line Posted at 2020-09-02 by jeffmer Hi, I have also being doing some measurements. I am using an M5StickC which has an 80x160 pixel ST7735S screen. I thought there was room for improvement for drawImage so I implemented a version of With Essentially the speed up is achieved by passing bigger chunks to the If the image is rotated, the performance disappears cf vertical lines, so perhaps we should see how that can be dealt with. However, rotation within an image is not a problem. What would be the best way of letting you all look at the code? Posted at 2020-09-02 by @MaBecker
share you branch via link. Posted at 2020-09-02 by jeffmer Thanks - not sure I got that quite right, however, you can see my version of Posted at 2020-09-02 by jeffmer There was a bug in |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-08-28 by jeffmer
I am developing a module for the ST7735S display on the MStick-C and have managed to get fairly reasonable performance using only Javascript. The module supports the palletted graphics
drawImage
routine to avoid having to do complete screen updates - I will post how to access this soon.To reduce the overall storage requirement, images are unpalletted and written to the device in chunks. I want to reduce the amount of buffer allocation and use only one permanently allocated buffer which holds a chunk of 16bit pixel data to write to SPI in one operation. The problem I have is that the last chunk will in general be a fragment and so I would like to only write a part of the chunk buffer. I tried using ArrayView as follows:
This does not work as b.buffer is in fact
g.chunkbuf.buffer
and consequently, the spi.write sends the whole chunk buffer rather than part of it. I have had to resort to allocating a new buffer for fragments as invar b =new Uint16Array(remnt)
. This allocates a new buffer each time which I am concerned may lead to problems with storage allocation due to fragmentation. Have I missed something obvious as to how to solve this? Ideally, I would likespi.write()
to have a size parameter.Beta Was this translation helpful? Give feedback.
All reactions