Jump to content

Joel Bodenmann

Administrators
  • Posts

    2,620
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Joel Bodenmann

  1. An STM32F4x9 with an ILI9488 configured in 3-wire SPI is probably the worst combination you can have. The STM32 peripheral doesn't provide 9-bit mode so you would have to bit-bang it which is very slow (and eats up all your CPU). Never the less, you can get it to work if that is all you desire.
    Otherwise, either use the ILI9488 in 4-wire SPI mode or set it to RGB parallel mode and use the LTDC peripheral - that is what it has been designed for.

    Most of these display modules have simple solder bridges / jumpers for the IM configuration pins. They are rarely "backed into the PCB" if you buy them from a reasonable vendor. Check the module you have. Maybe you can just reconfigure it with a simple solder job yourself without having to make a different purchase.

    If none of that is an option, and you really just want to get something to show up on the display, I think your only option is to bit-bang the interface as @inmarket mentioned.

     

    1 hour ago, PaulyLV said:

    If what he is saying is right, then all LCDs that need SPI initialization would ship with IM pins set to SPI interface.

    The point of those IM configuration pins is to select the correct hardware logic (inside of the chip) to talk the interface/protocol you specify. As the same physical pins are shared for different interface options the hardware needs to know which interface it should expect on those pins to setup the correct state machine, command decoder and probably a bunch of other things.
    Think of these IM pins as being similar to the LSB address pins of some I2C slaves: It's a permanent setting within your finished hardware/device but it's still different between different devices. Therefore, while those can be hard wired on your particular hardware they still need to be configurable.

    The table from the datasheet illustrates this:

    image.thumb.png.dbe89adba8737878f76caa20ea6fbc6b.png

    Just as a disclaimer: Personally, I have not all the details of the ILI9488 in my memory. However, the ILIxxxx chips tend to all work in similar fashions. But be sure to check the datasheet.

     

    1 hour ago, PaulyLV said:

    I tried to set all the bits on the "LCD red" pins and don't see anything. Did you mean setup LTDC first and then set the pins high/low? 

    Nah, that was just a long shot in case you would have gotten everything else right and the IM pins are configured for the RGB parallel interface.

     

    2 hours ago, PaulyLV said:

    I am desperate and willing to try anything to see something other than white on my display. :)

    If we may ask: Is this a hobby project? We do offer commercial/paid support where we directly work with customer's hardware to get things up and running. It's sort of our daily bread-and-butter.

  2. The IM pins only select the interface for the actual pixel data. Usually the physical display controller (ILI9488 in your case) will always listen for incoming commands on the SPI bus even after you started piping pixel data through a different interface. There are "things" you cannot do via the pixel interface such as changing contrast, gamma correction, backlight settings etc.

    If your display module is setup to expect pixel data via a parallel RGB interface (i.e. driver via LTDC) it will most likely definitely not react to any pixel data arriving via SPI.

    Obviously we have very little information on your situation but personally I'd recommend to just get LTDC up and running if your hardware is already designed for that anyway.
    Be sure to use the latest master branch from the µGFX git repository when using LTDC. We improved the LTDC driver since the last v2.9 release.

    If you're really desperate you could force the MSB of one of the colors (eg. blue) to high (or low) and check whether the display picks that up. Then you'd at least know whether everything is working :D

  3. STM32F429 indeed doesn't have 9-bit mode if I recall correctly. The STM32429i-Discovery and STM32F439i-Eval kits both use an STM32F4xx9 and an ILIxxxx controller connected via SPI (and then LTDC for pixel data). Those have the D/C pin hooked up to a separate GPIO if I'm not mistaken (at least a quick look at the ChibiOS example board files for those boards in the µGFX repository seems to confirm that).

    As long as you're seeing just a white screen initialization might not have completed successfully (which would again indicate either an incorrectly setup SPI or incorrect initialization sequence). There's not really a point in messing with pixel/color values. If the values are wrong you'll still see something changing on the display, it might just be incorrect colors but it won't stay completely white all the time. Just set it to RGB565 as that is the most common format and make it work with that first.

    5 hours ago, PaulyLV said:

    I changed the pixel format to RGB666 and attempted to send 3 bytes of data by calling write_data 3 times within gdisp_lld_write_color(). This causes the microcontroller to reset. Not good. 

    If the GDISP display driver is written somewhat correctly you really shouldn't have to modify any of gdisp_lld_xxx() functions in there unless you want to add features (or change the initialization sequence). I would recommend you to first of all properly verify that the signals on the SPI bus are actually correct (i.e. hook up a logic analzyer or oscilloscope and make sure that the waveforms are correct and look for the correct bytes written out by gdisp_lld_init()).
    Also make sure that other SPI configuration aspects are correct such as CPOL and CPHA settings. Also note that the ILIxxxx family of controller usually have a lower max SPI bus frequency for initialization/configuration compared to the actual pixel data stream once it is set up. That is what the post_init() function in the board file is usually there for (to change the SPI bus frequency). For now, just make sure that you have a low enough frequency until the thing actually works.
    You'll need to do verify this no matter whether you'll be piping out pixel data via SPI or via LTDC. SPI is always needed to initialize the display controller.

    Don't forget to compare the initialization sequence (in gdisp_lld_xxx()) with what your display module manufacturer provided you with. If they flipped the panel or something the configuration needs to reflect that (i.e. remapping pages/segments).

  4. 4 minutes ago, PaulyLV said:

    In function gDispGClear(), area = 320 X 480,

     for(; area; area--)
                    gdisp_lld_write_color(g);

    which means 'write_data' is called for each pixel, right?

    That is the fallback implementation if the underlying system doesn't provide any better means of filling a whole area with a solid color.
    If you look at the full implementation you'll notice that whenever possible we use hardware accelerated clearing, if that is not available we'd use hardware accelerated area filling, if that is not available we use color streaming and if that is not available the only option left is setting each pixel individually.

    The ILI9488 driver that ships with the library implements stream based access which means that we can setup a window and then stream each pixel value without addressing it individually.

    You'd certainly get a lot more performance on these things when using LTDC as it supports hardware acceleration (via DMA2D) which is implemented in the corresponding µGFX driver here.

     

    17 minutes ago, PaulyLV said:

    My team purchased the LCD from US Micro and received the initialization sequence from them.

    Have you checked whether that matches the implementation of gdisp_lld_init() here?

     

    18 minutes ago, PaulyLV said:

    The initial plan was to use RGB666 and LTDC but since we ran into some stumbling blocks like not realizing that a SPI connection is required to initialize the LCD in the first place, the LTDC plan was put on hold.

    Yes, that's correct. The LTDC interface is only there to stream the actual pixel/color values. You still need a side channel to actually initialize & configure the display controller (ILI9488).

     

    19 minutes ago, PaulyLV said:

    I am not sure what my expectation on the SPI bus should be.

    A good start would be to probe the bus and checking whether there is any activity at all. There's little benefit in checking the correct initialization sequence/parameters if you don't know whether the data actually appears on the physical bus correctly.

     

    20 minutes ago, PaulyLV said:

    I am not sure what my expectation on the SPI bus should be. Based on the ILI datasheet, SPI data for RGB666 looks like this but does that mean that each write_data() call would actually need to be called 3 times for each pixel which is why I asked about modifying  gdisp_lld_write_color() function.

    Some of the drivers that ship with the µGFX library have been contributed by community members (something we'll be separating for the next major release). I haven't checked the details but most likely the board file would ask you to acquire the bus (i.e. handle mutual exclusion on the HAL layer and setting CS low) and then simply call write_index() / write_data() for as many times as necessary. The driver will then ask you release the bus once it's done.
    It's also possible to extend the board file to use DMA if needed but generally you'd want to go LTDC anyway if that was your original plan.

  5. If you're using the current master branch of the v2 git repository you can use the built-in CMake integration. This way you can integrate the µGFX library into your CMake project the same way you'd integrate any other library shipping with a CMake find module.

    Add FindUgfx.cmake to CMAKE_MODULE_PATH:

    list(APPEND CMAKE_MODULE_PATH /path/to/ugfx/cmake)

    Include via find_package():

    find_package(
        ugfx
        REQUIRED
        COMPONENTS
            drivers/gdisp/SSD1312
    )

    Link target:

    target_link_libraries(
        ${TARGET}
        PRIVATE
            ugfx
    )

    Note that not all drivers have received the corresponding driver.cmake file yet which is why µGFX 2.10 has not been released yet. However, you can easily add them yourself (or you can let me know and I'll add it for you).

  6. Hello & Welcome to the µGFX community!

    I currently don't have time to look at the files you shared in detail but a few hints:

    • There is a bit of a history of issues with the ILIxxxx display controllers. There are quite a few knock-offs / clones and worst: Different silicon revisions that have different initialization sequences and the display module vendor doesn't tell you about it as the part name is literally the same. Did you get an initialization sequence from your module manufacturer/vendor? If so, try to replace that in gdisp_lld_ILI9488.c. This is basically the place where all the configuration happens. µGFX v3.0 has a nicer interface to do this without modifying the driver itself but we're not there yet.
    • If I remember correctly the ILI9488 driver that ships with the µGFX repository is by default setup for RGB565. Other color formats should work, but might require a different display controller initialization sequence/parameters (as described above). For the sake of testing, I'd try switching to RGB565 temporarily.
    • Have you probed your SPI bus? Does what you see match expectations?
    • You mentioned that you re-use a project that previously used a different display controller: Any chance that there is a stray setting for the color format somewhere? I.e. in your build system or the gfxconf.h configuration file?

     

    11 hours ago, PaulyLV said:

    I wonder if I am writing the data wrong in the gdisp_lld_write_color()

    Technically you shouldn't have to touch this to just use the µGFX library - especially if you can use an existing driver.
    If an existing driver is suitable you only need to implement the board file. Even if you need to implement your own driver the µGFX GDISP core will handle color conversions for you. That is actually why the driver config file has a setting for the low-level pixel format (i.e. the format the display controller expects).

     

    11 hours ago, PaulyLV said:

    or I should be enabling some other mode instead of GDISP_HARDWARE_STREAM_WRITE?

    For debugging you can disable both GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_READ if the situation requires so but generally you want to use those in case of the ILI9488 driver. If streaming is disabled, each pixel needs to be addressed individually which adds a lot of overhead especially on the SPI bus.

  7. You seem to be using the single-file-inclusion mechanism. Pretty much the only draw-back of using that mechanism is that multiple displays and pixmaps don't work as stated in the documentation: https://wiki.ugfx.io/index.php/Getting_Started#Single_File_Inclusion

    Quote

    Note: Some features such as multiple-display support and pixmaps are currently not supported when using the single-file-inclusion method.

    If you want to use pixmaps you can either directly use the Make or CMake files or manually add the µGFX source files to your existing build system.

  8. Just to be clear: When you talk about 'label', you're referring to the GWIN Label Widget created via gwinLabelCreate() correct?
    Does that label overlap the area of the graph?

     

    8 hours ago, crazybolillo said:

    [...] the axis disappears, the graph is still there as I can still draw points and they are displayed on screen. It seems as if the  axis disappear once the initialization function exits. If I redraw the axis in other parts of the code, they stay on screen. Weird but I guess its  solved.

    That would be because the graph is a window and not a widget (explained above).
    I do think that a better approach would be to promote the graph to become a widget too and then providing an interface to manage the plottable data. This is what most users of the graph widget end up doing anyway. Maybe we'll upgrade the built-in graph to facilitate this - Any feedback is welcomed :)

  9. I had a quick look between meetings and I think you're on the right track :)

    All three of your questions are basically answered the same way: You're essentially creating a custom widget which means that you have full control over all of these aspects. Unless I am missing something, everything is happening inside your gwin_custom_tabset.c implementation. It sounds silly but "just go through it and remove what you don't need".

    The first thing I'd recommend doing is remove all unused code (eg. stuff that is just there to make it play nicely with other built-in widgets (which isn't relevant when you create your custom widget). Notable that would be:

    • gwin_custTabsetDraw_image() (lines 579 to 613)
    • The true branch of GWIN_FLAT_STYLING (lines 403 to 429)

     

    On 01/09/2023 at 16:35, Vikash said:

    1.  In Tabs icons as well as text is showing up, if we try to remove the tab text, tab width is getting reduced. Please suggest how to make tab width constant.

    Given that you're basically creating a custom widget you have full control over these aspects.
    Have a look at the FixTabSizePos()

     

    On 01/09/2023 at 16:35, Vikash said:

    2.  We try to just show the icons, but it is not working.

    Can you explain what "not working" means? I guess that it's just a side effect of the existing tabset widget using the text width to size the tabs. Once you remove all the tab text logic (as you don't need that) you'll most likely manually size the tabs which will make this issue go away.
    Hint: Currently logic calls gdispGetStringWidth() at line 517. You want to replace that with something that suits you after you removed the tab texts.

     

    On 01/09/2023 at 16:35, Vikash said:

    3.  Also, we are not able to align icons to the center of each tab, it is always showing at the top left corner of tab.

    You've correctly added the function calls to render the icons via gdispGImageDraw(). To align the icons, just modify the x, y, width and height parameters of that function call.

     

    I hope that helps!

  10. Hello & Welcome to the µGFX community!

    A notable difference between the Graph and the Label is that the Graph is just a window whereas the label is a widget. The documentation explains the differences. The most important one for you to know is that a widget knows how to redraw itself whereas a window does not (widgets inherit from windows).

    The reason for the graph being just a window is that there wouldn't be any sensible way for us to know how to represent the data it shows in a generic, resource friendly manner. Most users either have a dedicated function to draw the entire graph (with data) and call that whenever necessary or they wrap it inside of a widget themselves.

    Once the graph is shown, it should not disappear unless the area gets cleared (eg. because you call gdispClear() or draw something else over it). Is it possible that this happens somewhere?

    I hope that helps. Please don't hesitate to ask if you have any further questions.

  11. The code attachments you provided don't seem to compile and seem generally incomplete.
    We'll gladly help wherever we can but we can't do guess work. Please provide a minimal example and explain what "does not work".

    I'd recommend you to either implement a custom widget from scratch (there is documentation on that as well as the aforementioned examples) or to copy the existing tabset and modifying it as needed.
    Your last post seems to go the right direction :)

  12. I just had a closer look at this. In case of anything inheriting from the container class, the custom draw is only responsible for the client area of the container which explains why this didn't work out for you.

    The proper way of doing this would be to implement a custom widget to facilitate your needs as demonstrated by the documentation and various existing widgets (there are also two examples in the downloads section).
    If you prefer a quick'n'dirty solution you could change the current drawtabs() implementation to render the tabs with images instead. You might be sneaky with some weak pointers here.

    Long term, the best approach would be to create a custom VMT for the Tabset and having a function pointer in there for the non-client-area drawing.

  13. Hello & Welcome to the µGFX community!

    You can customize the look'n'feel of any widget to match your needs. The easy approach here is to implement a custom drawing/rendering function for the existing widget. This means that you keep using the existing tabset widget behavior and you only change the way it is being rendered.
    There is a full example in the documentation showing how to add an icon to a pushbutton widget. The process will be the same for the tabset: https://wiki.ugfx.io/index.php/Creating_a_custom_rendering_routine

    You can use the void* parameter to pass in anything you like such as an images array or a complete custom type.
    This should cover any scenario where you are happy with the existing behavior but want more control over the visual look.

    In case that you also want to have different behavior, you can implement your own widget: https://wiki.ugfx.io/index.php/Creating_a_widget

  14. On 22/07/2023 at 19:46, Madyn said:

    With a lot of digging, I found that the acquire bus and release bus are supposed to control the SPI CS.

    That is indeed correct.
    The reason why it might be "ambiguous" is because the driver interfaces & board files are designed to be as agnostic as possible. There are scenarios where the same driver & display controller is used in a scenario where "acquire bus" and "release bus" does not simply translate to controlling the SPI CS.
    But in any case I agree that this should be documented more clearly - especially with some basic examples.

     

    On 22/07/2023 at 19:46, Madyn said:

    The system seems to work, however, it fails compilation when gfx.h/c is trying to find the configuration file.  Since it's apparently been configured by the makefile, it doesn't read compiler paths. 

    Just in case this isn't clear: The configuration file (gfxconf.h) is something that you have to provide. There is a sample file you can copy from the top-level directory of the µGFX library distribution (gfxconf.example.h). Usually you'd copy that and rename it to gfxconf.h and that's it. Where this is placed is entirely transparent to the µGFX library as long as you get your include paths correct (which is toolchain/buildsystem/IDE specific).

     

    On 22/07/2023 at 19:46, Madyn said:

    What I was looking for was a "this is what the project tree needs to look like, so your sources go here".  

    Given that the µGFX library was purposefully designed to be entirely agnostic to everything there is no "one-size fits all" solution from our side. However, a basic guideline can be:

    • If you use a Makefile based buildsystem, simply include the µGFX Makefile
    • If you use a CMake based buildsystem, simply include the µGFX CMake module
    • If you use some proprietary or non-standard build system or something hidden behind an IDE that is either difficult or impossible to modify, use the single-file-inclusion mechanism if you don't need multiple-display support
    • If none of the cases above work, put in the elbow grease and manually add the necessary C files & include paths to whatever system it is you're using essentially treating the µGFX library like "your own code".

    But in any case, just take the µGFX library source code and treat it as a black-box. i.e. copy paste the code somewhere on the filesystem. No matter what build system integration option you use this will ensure that you can upgrade transparently to newer versions down the road. Where you place this directory and how you manage that is up to the consuming project. We put a lot of effort into ensuring that it's entirely portable from our side.

     

    On 22/07/2023 at 19:46, Madyn said:

    Every program (and language, computer or otherwise) is created with the inborn assumption that "things will be done this way".  The larger the program, the more subtle, at times, the assumptions.  Now I'm beginning to understand the assumptions you made in this program.  Since I'm still setting things up, well, still figuring things out.

    That is reasonable :)
    There is the overall "architecture" documentation here:
    https://wiki.ugfx.io/index.php/Architecture
    There is a dandy chart in the GDISP documentation about the overall structure of the module:  https://wiki.ugfx.io/index.php/GDISP

     

    On 22/07/2023 at 19:46, Madyn said:

    I think I have the board file reasonably understood, but some of the configuration options are going to be interesting.  Since I don't (obviously!) write code the way you do, I'm still figuring out what I need to know. 

    Don't hesitate to ask if you have any questions. We'll gladly help out wherever we can.

  15. Hello & Welcome to the µGFX community!

    12 hours ago, Madyn said:
    • I want a graphics system I do not have to rewrite when larger projects go to Linux.
    • I want a graphics system that moves easily from project to project.

    You're certainly at the right spot then! This was one of the major design goals of the µGFX library.

     

    12 hours ago, Madyn said:

    adding uGFX by putting links in and changing some pathis works, but not gracefully.  Display inits, but rather complete lack of instructions on how to fill out the board file.  (DID find more information here about purpose of inlines, but that REALLY needed to be an inclusion in EVERY board file or at least obvious).  GetBus and ReleaseBus were not obvious, as was not the "leave the CS active at all times, thank you" until the bus is released. 

    Thank you for your feedback. I agree that more documentation should be added to the board files.
    Although it does not address your point (because it still doesn't properly document the required board file implementation) this resource might still help: https://wiki.ugfx.io/index.php/Display_Driver_Model

     

    12 hours ago, Madyn said:

    Problem with above scheme is that when trying to clear the display, converting your blue color yields a 0 when converted to native (ILI9341 should use RGB565).  Still puzzled about that.

    Can you provide a bit more information on this? What exactly do you mean by "converting your blue color yields a 0"?
    The GDISP driver is supposed to declare the correct pixel format: https://git.ugfx.io/uGFX/ugfx/src/branch/master/drivers/gdisp/ILI9341/gdisp_lld_config.h#L21
    From there, the µGFX library should handle color conversions correctly.

     

    12 hours ago, Madyn said:

    removing this and following instructions to addere uGFX as single file leads to puzzling placements, such as gfx.h, which then calls /src/gfx.h (which makes little sense right now).  Many inclusions remain unresolved. 

    The single-file-inclusion mechanism primarily exists to easily integrate the µGFX library into non-standard build systems (usually proprietary IDEs) as to avoid having to manually list all include paths and source files. The only disadvantage of using the single-file-inclusion mechanism is that multiple display support won't work (i.e. you can only ever have one display).
    You should not have to include anything yourself. The only thing you have to do is adding src/gfx_mk.c to your build system. Everything else inside the library itself is self-contained within that structure. Documentation on this is here: https://wiki.ugfx.io/index.php/Getting_Started#Single_File_Inclusion
    Can you provide more details on the issues you're encountering?
    Which build system are you using? The library itself supports Make and CMake out-of-the-box. Let me know if you need an example of how to use the µGFX library in a CMake scenario.

     

    12 hours ago, Madyn said:

    I also needed to rewrite the C++ routines to C (as separate routines) for things like the SPI driver.  While semaphores are not bypassed, my own C++ routines are meant to run on a per-transaction basis, with CS optionally down, run both register and data, then releasing the CS.  Again, protected by semaphores to make them thread safe.

    On the board-file level you can do pretty much anything you want including using C++ code.
    Note that the GDISP module provides a config flag GDISP_NEED_MULTITHREAD. If you set this to GFXON, the GDISP module maintains a mutex to facilitate threadsafety when accessing the actual display itself. This is entirely transparent in terms of API.

     

    12 hours ago, Madyn said:

    I don't really like trying to call C++ routines from C, and run into "unknown statement "class" and the like"  I bypass that by only calling C from C++.

    That is reasonable. When the µGFX library is used in a C++ environment the typical scenario is to write the board file implementation in plain C and simply using C++ for the application level stuff. The core library and the drivers usually take away all the heavy lifting so implementation of board files in C is pretty painless.

     

    12 hours ago, Madyn said:

    1) I'd like to know what the preferred directory structure is for uGFX, including all the included routines at the bottom of the stack.  By what's not linked, I don't think I have it right.

    What exactly do you mean by "preferred directory structure"? Usually you'd include the µGFX library and not touch it. Leave it as a self-contained 3rd-party software component. The only thing that goes into the consuming project itself is the configuration file (gfxconf.h) and the board file (or custom driver if needed).

     

    12 hours ago, Madyn said:

    Low level driver integration with an existing operating system seems to be a problem, and I do not wish to go to ChibiOS.

    Which problems are you observing? The idea is that the board file is simply #included which means that it can live anywhere as long as the path is in the compiler's include paths list.
    Furthermore, the board file is the only piece of software which interacts with the underlying OS / HAL. Therefore, it is easy to use anything you like (be it ChibiOS, FreeRTOS, Baremetal, Linux or anything else. The only thing that needs to be adapted is the board file.
    This design has served us well for over a decade and we haven't heard of any problems with this particular aspect yet. We'd be very keen on hearing more details on this so we can potentially improve the situation.

    If you can add a bit more detail to the issues you're encountering we'll gladly help & clarify where we can.

  16. You should be able to make the container larger than the display and then move it with `gwinMove()`.


    Alternatively, you might want to use the List widget which already implements proper scrolling: https://wiki.ugfx.io/index.php/List
    Note that this widget can be heavily customized to fit your needs. There is an example on the forum showing how to use it for an icon grid.

×
×
  • Create New...