PaulyLV Posted October 19, 2023 Report Posted October 19, 2023 Hello, I am new to working with LCD screens and uGFX. My setup uses STM32F429 with IAR EW and a ILI9488 (320 X 480) LCD. I have attached the uGFX files I modified. My goal is to display a splash screen on the display using SPI. As of now, the display flashes completely white and then dark. This corresponds in code to where the display is toggling between a 'Home' screen and an 'Error Message' screen (I am using an existing project that previously used ST7798). The hardware pins on the ILI9488 are set for 3-line SPI. I wonder if I am writing the data wrong in the gdisp_lld_write_color() function or I should be enabling some other mode instead of GDISP_HARDWARE_STREAM_WRITE? Could someone please give me some suggestions to try? Thanks! VID_20231011_221246358 (1) (1).mp4 board_ILI9488.h driver.mk gdisp_lld_config.h gdisp_lld_ILI9488.c
Joel Bodenmann Posted October 19, 2023 Report Posted October 19, 2023 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.
PaulyLV Posted October 20, 2023 Author Report Posted October 20, 2023 My team purchased the LCD from US Micro and received the initialization sequence from them. 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. For now, the goal is to get the LCD to display some color using SPI. In the initialization sequence, command 3Ah selects the interface and I think it is set to both DPI and DSI. 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.
PaulyLV Posted October 20, 2023 Author Report Posted October 20, 2023 Another question I had 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? I would expect to be able to write a color to the screen by writing a value in here but even that does not seem to be working. I feel like I am missing something fundamental about how the interface works.
Joel Bodenmann Posted October 20, 2023 Report Posted October 20, 2023 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.
Joel Bodenmann Posted October 25, 2023 Report Posted October 25, 2023 @PaulyLV Did you manage to get it working?
PaulyLV Posted October 25, 2023 Author Report Posted October 25, 2023 Joel, thank you for your earlier responses and for checking in. Unfortunately, I am still stuck on the flashing white screen. So far, I have tried to use 16-bit SPI since I technically need 9-bit transmission to send the D/C bit. No display. I used the original uGFX initialization routine for ILI9488 with RGB565 pixel format. Still flashing white screen. 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. The project I am using calls gDispClear and gDispFillArea periodically. I think my white screen is coming from these calls but no matter how I change the parameters, I cannot seem to see any colors on the screen. One of the SPI transmissions is in the attached image where the blue represents clock and the pink represents data. There are only 8 clock cycles but 9-bits of data. I wonder if this is what is causing the issue. Another colleague of mine also tried to "bit bang" the SPI interface but he sees a white screen as well. The only available data formats using 3-line SPI on ILI9488 are 8 colors or 262K colors. The current pixel format is set to RGB233.
PaulyLV Posted October 25, 2023 Author Report Posted October 25, 2023 If I compile a list of all the settings that are turned on between gfxconf.h and gfx_lld_config.h, maybe something will stand out as incorrect?
PaulyLV Posted October 25, 2023 Author Report Posted October 25, 2023 I turned on the gfx logo also but I don't see anything on the screen for that either. I guess I don't have the SPI connection working the way it is supposed to be. The white screen baffles me. I would expect blank screen if SPI was not working but I guess something is making it across and the LCD interprets that as all white. There are different brightness levels to the "white screen" if that makes sense. In gfxconf.h #define GFX_USE_OS_RAW32 GFXON #define GFX_OS_HEAP_SIZE 24000 #define GFX_USE_GDISP GFXON #define GDISP_NEED_VALIDATION GFXON #define GDISP_NEED_CIRCLE GFXON #define GDISP_NEED_MULTITHREAD GFXON #define GDISP_NEED_TEXT GFXON #define GDISP_NEED_TEXT_WORDWRAP GFXON #define GDISP_NEED_TEXT_KERNING GFXON #define GDISP_INCLUDE_USER_FONTS GFXON #define GDISP_NEED_IMAGE GFXON #define GDISP_NEED_IMAGE_GIF GFXON #define GDISP_NEED_IMAGE_BMP GFXON #define GDISP_STARTUP_COLOR Black #define GDISP_NEED_STARTUP_LOGO GFXON #define GFX_USE_GWIN GFXON #define GWIN_NEED_GRAPH GFXON #define GFX_USE_GFILE GFXON #define GFILE_NEED_ROMFS GFXON In gdisp_lld_config.h #define GDISP_HARDWARE_STREAM_WRITE GFXON #define GDISP_HARDWARE_CONTROL GFXON #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB233
inmarket Posted October 25, 2023 Report Posted October 25, 2023 Looking at the symptoms and your description it is obvious that you are still not talking SPI correctly to the display. Unfortunately you can't use SPI in 16 bit mode to emulate SPI in 9 bit mode. Unfortunately many micros are not able to talk 9 bit SPI, only 8 or 16. So, 1. Check carefully the data sheets of your micro to see if you can put the SPI port in true 9 bit mode 2. If it can't, see if the display has an 8 bit mode with a separate D/C line (most do). Note this requires an extra pin on your micro for the D/C line, or 3. Use bit banging instead of the micro UART. While this is a pain there is plenty of example code on the internet. At least this method can prove the working of the display and you can investigate a less CPU intensive solution later.
Joel Bodenmann Posted October 26, 2023 Report Posted October 26, 2023 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).
PaulyLV Posted October 26, 2023 Author Report Posted October 26, 2023 Thank you Joel and inmarket for your responses. Yes, STM32F429 supports only 8-bit and 16-bit SPI. The discovery board uses the 4-line SPI so 8-bit SPI would work since the data/command line is separate as you said and does not need to be transmitted over the SDA line. My teammate was able to get the 'All pixels on' command working with bit-banging SPI so the initialization sequence should be making it out but not able to see any color yet. When placing the order for the LCD, we had requested an 18-bit parallel interface. The status of the IM pins is confusing because if all LCDs need to be initialized using SPI then are the IM pins always set to serial interface? Then, what's the point of having the other configurations mentioned in the datasheet? I am checking with our LCD supplier to confirm the configuration of the IM pins on the LCDs we have. Would it be possible to display color via serial or parallel interface irrespective of the IM pins status based on what the initialization sequence does?
Joel Bodenmann Posted October 26, 2023 Report Posted October 26, 2023 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
PaulyLV Posted October 26, 2023 Author Report Posted October 26, 2023 The field engineer says that the IM pins on my LCD sample are hardwired for a 3-wire serial interface. If what he is saying is right, then all LCDs that need SPI initialization would ship with IM pins set to SPI interface. Then what is the point of having various settings for IM pins. This makes no sense to me. I am suspicious of the initialization code as well. Oddly enough, the 'All pixels on' command only works when the 'Display Function control'(B6h) command is using default parameters. Why one would affect the other is beyond me. I would assume the command should work no matter what your interface as long as the SPI connection is good. I am desperate and willing to try anything to see something other than white on my display. 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?
Joel Bodenmann Posted October 26, 2023 Report Posted October 26, 2023 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: 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.
PaulyLV Posted October 27, 2023 Author Report Posted October 27, 2023 Not a hobby project. I will let you know if we need paid support. Thank you for taking the time to respond to my questions.
Joel Bodenmann Posted October 29, 2023 Report Posted October 29, 2023 We'll of course also gladly continue answering any questions you might have here
PaulyLV Posted November 1, 2023 Author Report Posted November 1, 2023 I have an update. My teammate was able to get colors to display on the screen using the SPI interface. The initialization sequence had to be tweaked as well as the gdisp_lld_write_color function to use RGB666 pixel format. I will attach the initialization sequence in case it helps someone else using this LCD screen in the future. LLDSPEC void gdisp_lld_write_color(GDisplay *g) { // write_data(g, gdispColor2Native(g->p.color)); write_data(g, (gU8)((gdispColor2Native(g->p.color) & 0x0003F000) >> 10)); write_data(g, (gU8)((gdispColor2Native(g->p.color) & 0x00000FC0) >> 4)); write_data(g, (gU8)((gdispColor2Native(g->p.color) & 0x0000003F) << 2)); } gdisp_lld_init_ILI9488.txt
PaulyLV Posted November 1, 2023 Author Report Posted November 1, 2023 I am working on the LTDC portion now. Should I start a new topic, or can I continue to ask questions on this one?
Joel Bodenmann Posted November 2, 2023 Report Posted November 2, 2023 Glad to hear that you got it working! 22 hours ago, PaulyLV said: I am working on the LTDC portion now. Should I start a new topic, or can I continue to ask questions on this one? Up to you - I think this thread/topic was not overly specific to either SPI or LTDC.
PaulyLV Posted November 3, 2023 Author Report Posted November 3, 2023 (edited) I got the latest uGFX STM32LTDC functions and I set up LTDC with the following - single layer, pixel format RGB565, edited the width and height for ILI9488 but left the front porch, back porch settings as is. After I enable LTDC, I can see the HSYNC and VSYNC signals. The microcontroller resets during the call to gDispClear. I enabled the interrupt but I'm not really sure what needs to happen in the interrupt service handler. Are there any examples using uGFX STM32LTDC you could recommend? Not sure if the incomplete interrupt handler is causing the reset. Edited November 3, 2023 by PaulyLV
Joel Bodenmann Posted November 3, 2023 Report Posted November 3, 2023 9 hours ago, PaulyLV said: but left the front porch, back porch settings as is. Those settings are specific to yourr display panel. You'd get them from the corresponding datasheet. 9 hours ago, PaulyLV said: The microcontroller resets during the call to gDispClear. What exactly do you mean by that? Are you getting a brown-out event? 9 hours ago, PaulyLV said: Are there any examples using uGFX STM32LTDC you could recommend? Any high-level example in /demos should work. For board file examples you can have a look at the board files some of the STM32 eval/discovery boards that use LTDC. The STM32F746-Discovery comes to mind. Attached you can find a board file of some custom hardware I was working on recently. The hardware used an ST7701 display controller and the customer insisted on having the display controller configuration in a separate file so the board file simply calls ST7701_Init() and the rest is entirely specific to the LTDC driver. board_STM32LTDC.h
PaulyLV Posted November 7, 2023 Author Report Posted November 7, 2023 I commented out the gdisp_lld_draw_pixel function. This has stopped the microcontroller from resetting as soon as LTDC is enabled. The reset is from an exception frame. I wonder if has to do with the frame buffer address being that of an array stored in flash. I will need to look into that some more but for now I am trying to display an image to check if LTDC is working. I am using a header file for an image that I generated using a program called 'LCD_Image_converter' that I found online. I am able to display something with LTDC but it is not the right color and the resolution is really bad. My timing parameters are all within the range specified by the LCD datasheet. I am using the RGB565 pixel format but my hardware is connected for RGB666. I chose RGB565 since LTDC does not support RGB666. Could this be the reason I am getting such a pixelated image with wrong colors? Is the issue with the header file I am generating for the LCD? I tried using file2c program in uGFX and had less success. Any help you can provide is appreciated. HBP 4, HFP - 10, VBP - 2, VFP - 2 ( suggested by field engineer) H_Low - 41, V_Low - 10 (from IAR example for LTDC) LCDCLK freq - 12 MHz, HSync - 32 kHz, VSync - 64 Hz World480x320.BMP
Joel Bodenmann Posted November 7, 2023 Report Posted November 7, 2023 6 minutes ago, PaulyLV said: I commented out the gdisp_lld_draw_pixel function. This has stopped the microcontroller from resetting as soon as LTDC is enabled. The reset is from an exception frame. I wonder if has to do with the frame buffer address being that of an array stored in flash. Yes that is a likely cause. The µGFX library will try to write to the memory. It needs to be byte addressable. Usually you'd put the framebuffer in your SDRAM and setting the address(es) accordingly in the board file. 7 minutes ago, PaulyLV said: I am using a header file for an image that I generated using a program called 'LCD_Image_converter' that I found online. You might just as well use the file2c utility that ships as part of the µGFX library in conjunction with ROMFS which allows you to draw pictures from flash all within the cross-platform high-level µGFX API. However, that doesn't resolve the issue that you need to have a writable framebuffer that both LTDC and the CPU (µGFX) can access. 9 minutes ago, PaulyLV said: I am using the RGB565 pixel format but my hardware is connected for RGB666. I chose RGB565 since LTDC does not support RGB666. That will certainly cause a variety of problems. Just setup your hardware correctly (i.e. RGB565). The µGFX library does not really care tho. It supports a vast number of different pixel/color formats. Both RGB565 and RGB888 are known to work with the STM32LTDC driver. 10 minutes ago, PaulyLV said: I tried using file2c program in uGFX and had less success. Any help you can provide is appreciated. What problem did you encounter? Most likely you're running in the issue mentioned above: When drawing an image using the corresponding GDISP API the µGFX library will load your image (via ROMFS) and then draw that to the framebuffer (either via soft-copy or via DMA2D if enabled and applicable (it has some... restrictions regarding display orientation). Ignoring a lot of details it will basically "copy" your image located in FLASH to the framebuffer as needed. I would generally recommend not to spend time on trying to get stop-gap solutions working and instead making the system work properly as intended by ST. In your case this means having a large enough framebuffer to fit in at least one image (usually two, µGFX supports both a 2nd custom layer as well as built-in double-buffering) and configuring the system accordingly. In any case, it seems like you're almost there!
PaulyLV Posted November 10, 2023 Author Report Posted November 10, 2023 I definitely feel a step closer. I set up a smaller array in RAM and was able to display information that our product is supposed to display. The current design does not have SDRAM on it. Still trying to make a case that we need it. The requirement is to only update a certain process value on the screen each time but, as far as I can tell, LTDC will update the entire frame each time, correct? Even if I set up two layers, with the second layer only updating the process value I still need the minimum amount of RAM for one full frame (320 x 480 x 2bytes per pixel). I think the colors are messed up due to the hardware but since that is on the PCB I will have to wait for the next iteration of the board to check that. Is there a way to specify the pixel format in the 'file2c' utility? I ended up using the 'LCD image converter' which was actually working ok once I realized that it was the hardware that needs to be updated.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now