-
Notifications
You must be signed in to change notification settings - Fork 159
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
LCD_CAM: Code refactoring to prepare for future RGB panel implementation #1232
Conversation
Having common code shared sounds like a good idea. Unfortunately, I don't have the hardware to really test this. Would be nice if @Dominaezzz or @yanshay would have time to verify this |
Happy to assist, @seijikun - do you want me to test this PR on an I8080 device? Or want to make additional changes before I test? Also, when you test your RGB code I'd recommend testing in release mode. the I8080 example doesn't work well in release mode, seems like timing issues. BTW - what device are you using with the RGB code? I planned getting something along the lines of https://www.aliexpress.com/item/1005005529208137.html which says it's RGB, will it work with your code? |
Exactly. If you could run the I8080 example and verify that my refactoring didn't break anything, that would be nice!
I think that might be different for RGB devices, because they don't need timing-critical CPU intervention.
I'm using the Makerfabs ESP32-S3 Parallel TFT 4.3". I tried finding more information on the device from your link but couldn't find any more information than: "Interface: RGB". If that little piece of information is true, then it should. Though I don't want to make any promises, because even though I 1:1 cloned the esp-idf RGB-Panel implementation for testing, a two-color picture (one color upper half, second color lower half) currently looks like this VID_20240304_113106195.mp4 |
I'll have some time later this week to take a look and run the example. I also have a couple of Makerfabs RGB devkits so I can test an RGB driver if/when the time comes.
If you're streaming from PSRAM you'll want to drop the frequency real low to about 16Mhz. Also make sure you've set the timings correctly, the registers can be confusing to use. |
@Dominaezzz Oh you already have a working one? Could you please upload that somewhere? I think that could save me a lot of frustrating debug time. |
I tested, and strange results:
|
@yanshay If the release build worked, that sounds good! |
- Since both RGB and I8080 mode share most of their functionality, it makes sense to adopt esp-idf's architecture of the shared esp_ll HAL component for controlling the contained LCD peripheral.
Good news - it is now working! What was it in previous version that caused only in debug mode for a panic on subtract overflow where the code didn't have any subtraction? |
In Debug builds, Rust asserts if an integer operation would wrap. e.g.: let val0: u32 = std::env::args().len() as u32;
let val1: u32 = 9999;
let val2: u32 = val0 - val1; (I just used There were subtractions in |
I just noticed I was looking at the wrong |
@seijikun what frame rate do you reach on that device? at what PSRAM clock? |
Just for the record, we strongly discourage building using the I've considered making it a hard build error when not targeting (We should probably be more explicit about this!) |
@yanshay Oof, that's hard to know, since the updating happens transparently in the background. The manufacturer lists it as > 30 FPS, but quite frankly I don't know. PSRAM is running at 80MHz Octal (in esp-idf c++).
Oh, that's good to know. Thanks! |
Right, forgot about that. To see fps It's possible to use slow motion video recording (I did with iphone to verify my code metrics are more or less accurate) to see the screen updates and time. Not the most accurate but gives a feeling. Not critical though, just curious. |
Yeah, it's possible. You can read up about the different operation modes in the ESP32S3 LCD docs page. |
Short answer is yes but it's all very DIY.
Sure, I'll consider it when I get some spare cycles.
On that particular display the max FPS I was able to get was 83 FPS. Either using PSRAM or SRAM. |
.bit(cmd_cycles > 0) | ||
.lcd_cmd_2_cycle_en() | ||
.bit(cmd_cycles > 1); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you need an else here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea behind this interface with the optionals was basically that you can decide on calling-point which of the parameters you want to change. So basically:
set_phase_cycles(Some(0), None, Some(1));
means: Set cmd_cycles
to 0
, set data_cycles
to 1
, and leave `dummy_cycles´ unchanged.
I should probably clarify this in the docs of the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set
is the wrong verb, modify
, adjust
or update
would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After taking a my time to review, I don't see much value in matching esp-idf exactly. Frankly, trying to understand their *_ll.h
pattern has been a pain when trying grok how to talk to the ESP32 hardware and I would be sad to see that pattern followed here. Though I do see value in writing the common bits in the lcd module.
So to begin with, I don't think there's much point to the mode-specific functions, they should stay in the individual drivers for simplicity.
|
||
/// Reset the LCD peripheral's asynchronous TX FIFO buffer. | ||
#[inline(always)] | ||
pub fn fifo_reset(&self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn fifo_reset(&self) { | |
pub fn reset_async_fifo(&self) { |
.modify(|_, w| w.lcd_afifo_reset().set_bit()); | ||
} | ||
|
||
/// (I8080-Mode) Set the level of the DC line for different transaction phases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is I8080 specific, why bother having this method here? This can stay in the I8080 driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "(I8080-Mode)" comment is just a "typically used by" which was added by me.
The way I understood it from a short conversation with an Espressif engineer and from the datasheet, there is not actually a mode-specific
option. Even if you enable the chip's RGB-mode, some options (which are typically used for I8080 e.g.) would still work to cover certain use-cases.
That's why I followed their lcd_ll scheme: Because I'm not a big fan of making something as basic and as low in the system as a HAL too restrictive by encoding use-cases into the API. IMHO, those interfaces never really age well.
If you move I8080-specific functions to the I8080 class, you effectively prevent anyone who really knows what they are doing from working properly with the hardware by doing expert things.
But in the end, I guess it's for @jessebraham and @bjoernQ to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if you've seen #1282 or #31, but the general goal with the HAL as I see it is to provide restrictive set of APIs that enforce correct usage. It sounds like what you really want is a richer PAC (which I would kinda like too).
I haven't seen it discussed on this repo yet but I think there's plenty room for improvement when it comes to exotic use cases for a peripheral. The LCD_CAM was designed for LCDs and Cameras but really one could also use it for SPI, PARLIO, etc. The I8080 driver as is can even be used for MOTO6080 (though I couldn't find a good name to capture both so I went with the more popular one imo). And I think this is the point you're making about the lcd_ll scheme to provide flexibility without starting from scratch.
Whilst I 100% agree that a HAL should enable this flexibility, without a real use case to design for, it's impossible to design something sensible or review any design/refactor. Flexibility isn't free, so one needs to make sure they know what they're paying for and if it's worth it.
The current real use case I see here and I'm reviewing for is, "sharing code between the I8080 driver and the RGB driver".
With this in mind, I'm able to determine whether the method names make sense, whether functions like this one we're looking at (set_dc_level
) that sets multiple registers at once should be split up or not, or whether the function is needed at all.
At the moment this set_dc_level
has fantastic name and granularity for I8080 but for RGB it doesn't. For RGB it should have a different name and should only really care about data_phase
(and maybe idle_phase
, but in practice once the driver is started in RGB mode it typically needs to continuously run forever).
The only reason I'm able to make this judgement is because we have a real use case to discuss. If we want to handle every possible use case ever, then a richer PAC is simply the answer.
Just my opinion at least. I'll wait for the esp-hal maintainers to comment before I review further as I don't want to waste time and brain power making comments that the hal doesn't care for.
@JurajSadel any updates on the LCD devkit we ordered to test this driver? |
Unfortunately, it hasn't arrived yet. |
Hello guys, finally, I received a HW so I can test/help with this PR. |
#[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
#[repr(u32)] | ||
pub enum LcdClockSource { | ||
#[default] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this the default? I'd expect the default to be no clock, so Option<LcdClockSource>
with a default of None
.
@JurajSadel Mind running the example in Also which devkit do you have? |
@Dominaezzz I ran the example (original one and also with this refactoring changes) and in debug, it works as expected (bleu and red) but in release it's black and white. I've been playing a bit with the delays and tried figured out what might be the issue here, but no luck yet. I will continue looking into that a little bit more. However, the issue is not related to this PR so maybe we can wrap it up? |
Hello @seijikun, sorry I don't have time right now to investigate the release profile issue (not related to this PR, though!). It would be nice if we could wrap up and finish this PR for final review, from my perspective LGTM, however,r rebase is needed. Would you mind doing that, please, or should we find someone to handle that? |
I would really like to get this wrapped up, @seijikun are you able to rebase this branch, or should we get @JurajSadel to take over here? |
We're kinda blocked on this thread #1232 (comment) before this can be wrapped up. So if you could comment on it that would help |
@seijikun Thanks for the PR! I'm not sure adding flexibility for the sake of flexibility is a good idea in the long run. Do you have any plans for a follow up to this? |
@MabezDev Originally, that was my plan. I also have (not yet working) experiment code for it (results can be seen from the video above). W.r.t merging this MR, like @Dominaezzz said, it depends on what the focus of |
Thanks for the update. I think I am going to go ahead and close this PR at this point, thank you regardless for your contributions. Any conversation(s) can be continued in issues/discussions, and perhaps once we have made some decisions this can be revived and/or revisited in the future :) |
Must
errors
orwarnings
.cargo fmt
was run.CHANGELOG.md
in the proper section.Nice to have
This PR basically implements
esp-idf
's internal lcd_ll HAL on the commonLcd<'d>
struct with all the common functionality shared between I8080 and a potential future RGB implementation.In @Dominaezzz 's implementation, all of this register pushing was located inside the
I8080
implementation. I attempted to port most of this from code insideI8080
to calling this shared functionality, but there were some places I didn't dare to touch since I don't have the hardware. (I have a RGB-Bus display that I plan to play around with though)I have multiple reasons for this change:
esp-idf
upstream, which is IMHO never a bad ideaWould be nice if someone could verify my changes by running the I8080 example on suitable hardware.
This can be seen as an RFC of sorts. If this is deemed an acceptable change, I will add an entry to the changelog.