-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
transferImageDMA image pointer is non-const #1478
Comments
The pushImageDMA function will re-arrange the data if it needs to be clipped to a display window, or if bytes need to be swapped so a const will not work. It is important that it behaves just like pushImage in this respect. In your case I suspect pushPixelsDMA is a better option with the byte swap option removed and the pointer being const. Thus a new function is needed. |
Is it something you’re willing to put in a newer revision? I really need to const this. Basically what I’m doing is writing bindings for my graphics library, GFX
https://www.codeproject.com/Articles/5302085/GFX-Forever-The-Complete-Guide-to-GFX-for-IoT
It’s cross platform, and does things like True Type, and progressive JPEG loading, and I use it in my commercial projects. I would have just written my own driver (as I already have several display drivers for this)
Trouble is, I don’t how you got that parallel 8-bit driver to work. Even using your code as a guide (GFX is also MIT licensed)
I could not get any signs of life from the thing, so instead I’m binding to your driver. That’s fine, as your driver is fast, and the only real downside to it is the way it’s implemented I don’t think you can use it to control multiple displays.
But I use const buffers for draw sources for a lot of reasons. I’m willing to use this pushPixelsDMA option but again, it needs to take a const buffer for me to do it. Right now I am calling your driver synchronously in all cases, even though my GFX library supports asynchronous operations if the driver does.
Best regards,
honey the codewitch
PS: You're probably busy but I'd like to pick your brain a bit about your use of macros as opposed to say __attribute((always_inline)) for things like the WR_L macro.
What i did in my implementation was make a sttic function for it, and then always inline it.
I used pin mappings as template arguments to my driver, and that serves two purposes - it creates compile time bindings to the right pins without polluting the global namespace with preprocessor macros, and it makes it so static declarations are specific to a particular template instantiation meaning you can run more than one screen at once, even with statics. Is there a reason you wouldn't go this route? To be honest I never got it to work.
|
The DMA features in the library only work with SPI interface displays, not 8 bit parallel. SPI DMA is supported for a limited number of functions for ESP32, some STM32 processors and the RP2040. I am not sure which processor you are using, if it is the ESP32 then it is possible to get 8 bit parallel DMA working using the I2S interface features, but my experiments have not been very successful. With the RP2040 processor I do intend to add 8 bit parallel DMA using the PIO features but it will be quite a while before that hapens. Given all that, I can add a const type DMA block transfer without window clipping and byte swapping, this would be quite a trivial change as is is just a case of cut paste and edit. Yes, the macros have proliferated and there are better ways of managing this. It is just how the library evolved so don't look for some deep and meaningful reasons! |
I would absolutely love it if you added that const function. I preclip everything anyway, so it would just be duplicating effort.*** I realize that the DMA isn't available for parallel since the whole thing is bit banged with no hardware support. The thing is, I want my bindings to work with your driver regardless, and take advantage of whatever is there, so if the user configures your driver to run SPI on an ESP32, async ops in my library will actually async instead of running synchronously. I never figured on using the I2S that way. I didn't even think you could map more pins that way, but maybe I misunderstand you. I thought I2S was only a handful of pins (I haven't used it before) Thank you for the clarification on the macros. It's totally understandable that the code would evolve, and there is no reason. I was just trying to sniff around as to why my code wasn't working, even though I (thought) I was following your code. I even diffed all the pin highs and lows (except the data pins) after dumping the output to the serial port for every pin change and data write, and compared the diffs between your driver and mine. No change. I am totally flummoxed, so I guess I'm binding to your driver. I notice yours has antialiased fonts now, so it makes it a bit more competitive with my True Type engine in GFX (which is only fast on a WROVER due to memory constraints) but since I pick assets based on what clients want it's nice that they can have their designers send me a TTF or OTF font to use. =) *** regarding clipping, rather than rearranging memory, when it's not just the bottom or top that's clipped in which case I just change offsets/lengths, I fall back to a line by line draw of the bitmap and offset+adjust the stride - it doesn't let you do full DMA that way, HOWEVER, on the ESP-IDF you can queue several async transactions, so in my ESP-IDF drivers it will actually transfer chunks of the clipped bitmap via DMA by queuing several (partial) lines of the bitmap at time. It's more expensive than your method either way, but it allows clipping in place without rearranging, sacrificing some performance as a result. Eventually I plan on making GFX able to dynamically allocate buffers on the fly for situations like this or alpha blending/anti-aliasing when using them can increase performance |
I have created a branch 1478 for you to try. |
Thank you. I'll give it a shot and let you know it goes. I'm assuming if it works, that it will eventually be rolled into the main branch? That's what I'd need in order to viably redistribute my bindings for your driver with Async support added to them. |
I tried it. It works fantastically. Thank you so much. I'm curious though, since you made the pushImageDMA function const, I take it you're no longer clipping and such. Wouldn't it be advisable to make a second function for the const version so that you don't change the behavior of existing code? Of course this only applies if you intend to update the main branch with this revision, which I hope you do because that way my bindings can work for other people as well. =) |
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer)
should be
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t* image, uint16_t* buffer)
The reason being is images are often const and it is impossible to do asynchronous transfers with const sources because of the way you have implemented this.
There's a better way to do it, but you're using buffer to point to image in the routine and that's a non-starter.
Please fix this, as I will have to fork your code otherwise.
The text was updated successfully, but these errors were encountered: