Jump to content

CubeMXIDE on a custom hardware board with ILI9341, some basic help needed.


Madyn

Recommended Posts

There are about three or so things I need help with at the moment.  I do need to describe the hardware, though, and the existing software environment.

Hardware:

  1. ARM processor, 2M * 32 QSPI memory, displays connected by SPI, one display on one port, touch controller (XPT on another SPI, not yet debugged).
  2. Existing ILI9341 display working with my own graphics system on SPI1. 
  3. I want a graphics system I do not have to rewrite when larger projects go to Linux.
  4. I want a graphics system that moves easily from project to project.
  5. FreeRTOS is used, with lower level hal drivers encapsulated by higher level HAL drivers in C++, with more controls and adapted to writing to memory or displays.  Allows control of A0, RW, CS, lines within the driver.  Drivers are also semaphore protected against multiple thread accesses.

Software:  all written in C++ (graphics system allowed panels to own objects, drawing a panel automatically drew the children).  Hexdumps, animated icons, interactive windows, geometric primitives are implemented.  Rest of operating system is written in C++, interfaces to FreeRTOS (c). 

Problems:

  1. 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. 
  2. 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.
  3. 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. 
  4. 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.
  5. 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++.

 

Again, my stuff works, drivers work, and so on (graphics drivers write to virtual 32 bit image which can be read by the graphics program, updates translate the image to the display's format and assume write only.)

oh, and for whatever reason, the Chinese display boards don't really like reading back data (or even registers....)  I'll have to look into that.

 

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.

2) some more documentation would be appreciated on actually filling the board_xxxx files and why.

3) I might help with that once I understand what's going on.

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

You're going to get some requests sooner or later to port to Azure.  Can't help, won't help, won't work for me because of the way I structure things and the limitations of Azure and C++

Comments are welcome;

 

Harvey

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Quote

Thank you for your feedback. I agree that more documentation should be added to the board files.

With a lot of digging, I found that the acquire bus and release bus are supposed to control the SPI CS. (very helpful post from one of your experts).

I've done two projects.  One linked everything in, and attempted to compile each routine along with the rest of them.  This required some considerable changing of paths to allow compilation.  (Yes, I know now that wasn't the preferred way).  In clearing the screen (I used one of my own drivers for the ILI9341), your fill routine takes the background color (in this case, blue, your definition of blue), then converts it to the native display format.  That macro returned a zero, which was used to clear the screen.  I wanted blue as a test.  Perhaps a bit more documentation on *when* a particular macro is chosen might help.  However, putting that aside to try to do the "right" version of including the software:  the following happens:

Quote

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.

 

This is CubeMXIDE, with which I have had some issues.  However, it works for my projects.  I have a common library for all of my projects where possible, and link to the sources.  An options file uses #ifdef to include and #define to customize features, dropping out, for instance an LED control chip and defining how it can be accessed.  That works.  I followed some directions about setting up Eclipse (on this forum), imported the whole directory of uGFX, moved the config file up to the core/inc directory, put the makefile.c into the core/src directory, made the entire uGFX addition excluded from compilation.  Added the gfxinit file to the main bridge program.  (I have the main.c as provided by the CUBEMXIDE, which is modified to add QSPI memory.  That program then calls a C++ program (CPP_LINK) which sets up my wrappers around the low level HAL drivers and can (did) initialize displays.  The call to GFXinit is there.  FreeRTOS is already started, and CPP_LINK then creates the main application as a loop, which goes on to initialize all the system interfaces (C++, packet capable). 

I haven't modified the build system from what CubeMXIDE provides.  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. 

So at this point, no compilation on the second try, but it does seem to be more of what you intend. 

Quote

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.

What I did was to rewrite (in this case) the SPI drivers so that they were C routines (I kept the original C++ drivers intact).  If I use the same semaphore on my code, the drivers interlock.  Interfaces are protected at the system driver level, and the entire device (display, memory chip, etc) is protected at the system device level.  I think I'll have to use my semaphores, though.  (semaphores are not owned by the SPI driver class, so they're accessible to C code).

The low level code in the board file is C, not C++, so that's not a problem.  My original C++ routines do more heavy lifting.  ex: controlling the A0 line and CS so that the entire transaction is done as:  CS down, A0 down, send x bytes of command, A0 up, send y bytes of data, CS up, A0 down (just so it's in a known state).  I also reset the SPI timing on the interface as needed, in case the interface is shared by two different chips (hardware SPI enables NOT used).

 

Quote

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).

What I was looking for was a "this is what the project tree needs to look like, so your sources go here".   since you never have the IDE compile the program, it matters a bit less, but I was looking more for a "do this and here's what we expect" kind of approach. 

Quote

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.

I'm getting that idea now, which is ok.  I see the idea of the boardfile and why you did it like that. 

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.

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. 

Thanks for the help, I need to figure out how some of those paths are resolved. 

I prefer to know why, so if it doesn't work, I can figure out how to fix it. 

Harvey

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...