Arthur O. Posted December 6, 2019 Report Posted December 6, 2019 Hi, I'm currently tryying to implement an ILI9341 using an STM32F429, HAL, cmsis_os2 and uGFX, programming in SW4STM32. As i'm working in an RT environment, i declared gfxInit() in the very first task running, which terminates itself after running. Everything compiles fine but thta's during debug that things go south, let me explain. From peripheral inits to kernel strating, everything's fine. In debug mode in gfxInit(), it goes through to _gdispInit() and then gDriverRegister() as intended. But eventhough i changed GDISP_TOTAL_DISPLAYS to 1 instead of 2 by default and defining GDISP_DRIVER_LIST which was set to GDISPVMT_Win32, GDISPVMT_SSD1306 to GDISPVMT_ILI9341 in gdisp_options.h, it won't callback _gdispInitDriver to launch the gdisp_lld_init function and other write functions. What's the actual problem then ? When calling gdispFillStringBox() and going through it in debug mode, i noticed that the instructions g->p.x through g->p.cy don't actually do anything (the values don't change after those calls according to the debug), same deal when manually calling gdisp_lld_init() in my test thread, with instructions g->g.width through g->g.Contrast, which don't actually change the value in the g struct. This results in the fillarea(g) call from gdispFillStringBox to cycle through 44M values (area = g->p.cx * g->p.cy). Note that when manually calling gdisp_lld_init(), my ILI9341 get reset and initialized fine, but the first gdispFillStringBox() gets pulled into that 44M values for(;;) loop. I know that GDISP (the default display) and the GDisplay overall struct is a blackbox, but i can't quite understand why internal uGFX calls and API functions can't change the attributes of the GDisplay object. I'm linking relevant files thereafter. Thanks in advance for our answer and the time you'll take to help me ! Cheers, Arthur gdisp_lld_ILI9341.c /* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.io/license.html */ #include "gfx.h" #if GFX_USE_GDISP #if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT) #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.") #endif #undef GDISP_SCREEN_WIDTH #undef GDISP_SCREEN_HEIGHT #endif #define GDISP_DRIVER_VMT GDISPVMT_ILI9341 #include "gdisp_lld_config.h" #include "../../../src/gdisp/gdisp_driver.h" #include "board_ILI9341.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ #define dummy_read(g) { volatile gU16 dummy; dummy = read_data(g); (void) dummy; } #define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } #define write_data16(g, data) { write_data(g, data >> 8); write_data(g, (gU8)data); } #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) static void set_viewport(GDisplay *g) { write_index(g, 0x2A); write_data(g, (g->p.x >> 8)); write_data(g, (gU8) g->p.x); write_data(g, (g->p.x + g->p.cx - 1) >> 8); write_data(g, (gU8) (g->p.x + g->p.cx - 1)); write_index(g, 0x2B); write_data(g, (g->p.y >> 8)); write_data(g, (gU8) g->p.y); write_data(g, (g->p.y + g->p.cy - 1) >> 8); write_data(g, (gU8) (g->p.y + g->p.cy - 1)); } /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ LLDSPEC gBool gdisp_lld_init(GDisplay *g) { // No private area for this controller g->priv = 0; // Initialise the board interface init_board(g); // Hardware reset setpin_reset(g, gTrue); gfxSleepMilliseconds(20); setpin_reset(g, gFalse); gfxSleepMilliseconds(20); // Get the bus for the following initialisation commands acquire_bus(g); write_index(g, 0x01); //software reset gfxSleepMilliseconds(5); write_index(g, 0x28); // display off //--------------------------------------------------------- // magic? write_index(g, 0xcf); write_data(g, 0x00); write_data(g, 0x83); write_data(g, 0x30); write_index(g, 0xed); write_data(g, 0x64); write_data(g, 0x03); write_data(g, 0x12); write_data(g, 0x81); write_index(g, 0xe8); write_data(g, 0x85); write_data(g, 0x01); write_data(g, 0x79); write_index(g, 0xcb); write_data(g, 0x39); write_data(g, 0x2c); write_data(g, 0x00); write_data(g, 0x34); write_data(g, 0x02); write_index(g, 0xf7); write_data(g, 0x20); write_index(g, 0xea); write_data(g, 0x00); write_data(g, 0x00); //------------power control------------------------------ write_index(g, 0xc0); //power control write_data(g, 0x26); write_index(g, 0xc1); //power control write_data(g, 0x11); //--------------VCOM write_index(g, 0xc5); //vcom control write_data(g, 0x35);//35 write_data(g, 0x3e);//3E write_index(g, 0xc7); //vcom control write_data(g, 0xbe); // 0x94 //------------memory access control------------------------ write_index(g, 0x36); // memory access control write_data(g, 0x48); //0048 my,mx,mv,ml,BGR,mh,0.0 write_index(g, 0x3a); // pixel format set write_data(g, 0x55);//16bit /pixel //----------------- frame rate------------------------------ write_index(g, 0xb1); // frame rate write_data(g, 0x00); write_data(g, 0x1B); //70 //----------------Gamma--------------------------------- write_index(g, 0xf2); // 3Gamma Function Disable write_data(g, 0x08); write_index(g, 0x26); write_data(g, 0x01); // gamma set 4 gamma curve 01/02/04/08 write_index(g, 0xE0); //positive gamma correction write_data(g, 0x1f); write_data(g, 0x1a); write_data(g, 0x18); write_data(g, 0x0a); write_data(g, 0x0f); write_data(g, 0x06); write_data(g, 0x45); write_data(g, 0x87); write_data(g, 0x32); write_data(g, 0x0a); write_data(g, 0x07); write_data(g, 0x02); write_data(g, 0x07); write_data(g, 0x05); write_data(g, 0x00); write_index(g, 0xE1); //negamma correction write_data(g, 0x00); write_data(g, 0x25); write_data(g, 0x27); write_data(g, 0x05); write_data(g, 0x10); write_data(g, 0x09); write_data(g, 0x3a); write_data(g, 0x78); write_data(g, 0x4d); write_data(g, 0x05); write_data(g, 0x18); write_data(g, 0x0d); write_data(g, 0x38); write_data(g, 0x3a); write_data(g, 0x1f); //--------------ddram --------------------- write_index(g, 0x2a); // column set // size = 239 write_data(g, 0x00); write_data(g, 0x00); write_data(g, 0x00); write_data(g, 0xEF); write_index(g, 0x2b); // page address set // size = 319 write_data(g, 0x00); write_data(g, 0x00); write_data(g, 0x01); write_data(g, 0x3F); // write_index(g, 0x34); //write_index(g, 0x35); // tearing effect off // tearing effect on // write_index(g, 0xb4); // display inversion // write_data(g, 0x00); write_index(g, 0xb7); //entry mode set write_data(g, 0x07); //-----------------display--------------------- write_index(g, 0xb6); // display function control write_data(g, 0x0a); write_data(g, 0x82); write_data(g, 0x27); write_data(g, 0x00); write_index(g, 0x11); //sleep out gfxSleepMilliseconds(100); write_index(g, 0x29); // display on gfxSleepMilliseconds(100); // Finish Init post_init_board(g); // Release the bus release_bus(g); /* Turn on the back-light */ set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = (gCoord) GDISP_SCREEN_WIDTH; g->g.Height = (gCoord)GDISP_SCREEN_HEIGHT; g->g.Orientation = gOrientation0; g->g.Powermode = gPowerOn; g->g.Backlight = (gCoord)GDISP_INITIAL_BACKLIGHT; g->g.Contrast = (gCoord)GDISP_INITIAL_CONTRAST; return gTrue; } #if GDISP_HARDWARE_STREAM_WRITE LLDSPEC void gdisp_lld_write_start(GDisplay *g) { acquire_bus(g); set_viewport(g); write_index(g, 0x2C); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { write_data16(g, gdispColor2Native(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); } #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDisplay *g) { acquire_bus(g); set_viewport(g); write_index(g, 0x2E); setreadmode(g); dummy_read(g); } LLDSPEC gColor gdisp_lld_read_color(GDisplay *g) { gU16 data; data = read_data(g); return gdispNative2Color(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (gPowermode)g->p.ptr) return; switch((gPowermode)g->p.ptr) { case gPowerOff: case gPowerSleep: case gPowerDeepSleep: acquire_bus(g); write_reg(g, 0x0010, 0x0001); /* enter sleep mode */ release_bus(g); break; case gPowerOn: acquire_bus(g); write_reg(g, 0x0010, 0x0000); /* leave sleep mode */ release_bus(g); break; default: return; } g->g.Powermode = (gPowermode)g->p.ptr; return; case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (gOrientation)g->p.ptr) return; switch((gOrientation)g->p.ptr) { case gOrientation0: acquire_bus(g); write_reg(g, 0x36, 0x48); /* X and Y axes non-inverted */ release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case gOrientation90: acquire_bus(g); write_reg(g, 0x36, 0xE8); /* Invert X and Y axes */ release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case gOrientation180: acquire_bus(g); write_reg(g, 0x36, 0x88); /* X and Y axes non-inverted */ release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case gOrientation270: acquire_bus(g); write_reg(g, 0x36, 0x28); /* Invert X and Y axes */ release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; } g->g.Orientation = (gOrientation)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; //case GDISP_CONTROL_CONTRAST: default: return; } } #endif #endif /* GFX_USE_GDISP */ My test task StartLCDTask in main.c, that has a .stack_size of 1280. void StartLCDTask(void *argument) { gCoord width, height, x, y; width = height = x = y = 0; // Initialize the display HAL_GPIO_WritePin(RST_LCD_GPIO_Port, RST_LCD_Pin, GPIO_PIN_SET); // Get the screen size width = gdispGetWidth(); gFont font1, font2; gCoord fheight1, fheight2; const char *line1, *line2; char buf[8]; // Initialize and clear the display // Get the screen size width = 240; // Get the fonts we want to use font1 = gdispOpenFont("DejaVuSans10*"); font2 = gdispOpenFont("UI1*"); //font2 = gdispOpenFont("Geosans*"); //font2 = gdispOpenFont("Free*"); //font2 = gdispOpenFont("Hellovetica*"); //font2 = gdispOpenFont("babyblue*"); //font2 = gdispOpenFont("PF Ronda*"); //font2 = gdispOpenFont("Apple*"); y = 0; fheight1 = gdispGetFontMetric(font1, gFontHeight)+2; fheight2 = gdispGetFontMetric(font2, gFontHeight)+2; line1 = "Check out my FONTS STM32F4"; line2 = "0123456789~!@#$%^&*_-+=(){}[]<>|/\\:;,.?'\"`"; // Font 1 gdispFillStringBox(0, y, width, 20, line1, font1, GFX_BLACK, GFX_WHITE, gJustifyCenter); y += fheight1+1; gdispFillStringBox(0, y, width, 40, line2, font1, GFX_BLACK, GFX_WHITE, gJustifyCenter); y += fheight1+1; // Font 2 gdispFillStringBox(0, y, width, fheight2, line1, font2, GFX_BLACK, GFX_WHITE, gJustifyCenter); y += fheight2+1; gdispFillStringBox(0, y, width, fheight2, line2, font2, GFX_BLACK, GFX_WHITE, gJustifyCenter); y += fheight2+1; // Font 1 drawing White on the (GFX_WHITE) background gdispDrawStringBox(0, y, width, fheight1, line1, font1, GFX_WHITE, gJustifyCenter); y += fheight1+1; gdispDrawStringBox(0, y, width, fheight1, line2, font1, GFX_WHITE, gJustifyCenter); y += fheight1+1; // Show Sizes buf[0] = (fheight1-2)/10 + '0'; buf[1] = (fheight1-2)%10 + '0'; buf[2] = ','; buf[3] = ' '; buf[4] = (fheight2-2)/10 + '0'; buf[5] = (fheight2-2)%10 + '0'; buf[6] = 0; gdispFillStringBox(0, y, width, fheight1, buf, font1, GFX_RED, GFX_WHITE, gJustifyCenter); /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { osDelay(1); } /* USER CODE END 5 */ } gfxconf.h #define GFX_USE_OS_CMSIS2 GFXON #define GFX_OS_NO_INIT GFXON #define GFX_USE_GDISP GFXON #define GDISP_NEED_VALIDATION GFXON #define GDISP_NEED_CIRCLE GFXON #define GDISP_NEED_MULTITHREAD GFXON #define GDISP_NEED_STREAMING GFXON #define GDISP_NEED_TEXT GFXON #define GDISP_NEED_UTF8 GFXON #define GDISP_INCLUDE_FONT_UI1 GFXON #define GDISP_INCLUDE_FONT_DEJAVUSANS10 GFXON #define GFX_USE_GTIMER GFXON board_ili9341.h #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H #include "main.h" #define LCD_DC_CMD HAL_GPIO_WritePin(DC_LCD_GPIO_Port, DC_LCD_Pin, GPIO_PIN_RESET) #define LCD_DC_DATA HAL_GPIO_WritePin(DC_LCD_GPIO_Port, DC_LCD_Pin, GPIO_PIN_SET) #define LCD_RST_SET HAL_GPIO_WritePin(RST_LCD_GPIO_Port, RST_LCD_Pin, GPIO_PIN_SET) #define LCD_RST_RES HAL_GPIO_WritePin(RST_LCD_GPIO_Port, RST_LCD_Pin, GPIO_PIN_RESET) #define LCD_CS_RES HAL_GPIO_WritePin(CS_LCD_GPIO_Port, CS_LCD_Pin, GPIO_PIN_RESET) #define LCD_CS_SET HAL_GPIO_WritePin(CS_LCD_GPIO_Port, CS_LCD_Pin, GPIO_PIN_SET) /** * SPI configuration structure. * Speed 12 MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. * Soft slave select. */ SPI_HandleTypeDef hspi4; static void send_data(gU16 data); /** * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure * * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ static void init_board(GDisplay *g) { // As we are not using multiple displays we set g->board to NULL as we don't use it. g->board = NULL; LCD_CS_SET; LCD_DC_CMD; } /** * @brief After the initialisation. * * @param[in] g The GDisplay structure * * @notapi */ static void post_init_board(GDisplay *g) { (void) g; LCD_DC_DATA; } /** * @brief Set or clear the lcd reset pin. * * @param[in] g The GDisplay structure * @param[in] state gTrue = lcd in reset, gFalse = normal operation * * @notapi */ static void setpin_reset(GDisplay *g, gBool state) { (void) g; if (state == -1) { LCD_RST_RES; } else { LCD_RST_SET; } } /** * @brief Set the lcd back-light level. * * @param[in] g The GDisplay structure * @param[in] percent 0 to 100% * * @notapi */ static void set_backlight(GDisplay *g, gU8 percent) { (void) g; (void) percent; } /** * @brief Take exclusive control of the bus * * @param[in] g The GDisplay structure * * @notapi */ static void acquire_bus(GDisplay *g) { (void) g; LCD_CS_RES; } /** * @brief Release exclusive control of the bus * * @param[in] g The GDisplay structure * * @notapi */ static void release_bus(GDisplay *g) { (void) g; LCD_CS_SET; } /** * @brief Send data to the lcd. * * @param[in] data The data to send * * @notapi */ static inline void send_data(gU16 data) { HAL_SPI_Transmit(&hspi4, &data, sizeof(data), HAL_MAX_DELAY); } /** * @brief Send data to the index register. * * @param[in] g The GDisplay structure * @param[in] index The index register to set * * @notapi */ static inline void write_index(GDisplay *g, gU16 index) { (void) g; LCD_DC_CMD; send_data(index); LCD_DC_DATA; } /** * @brief Send data to the lcd with DC control. * * @param[in] g The GDisplay structure * @param[in] data The data to send * * @notapi */ static inline void write_data(GDisplay *g, gU16 data) { (void) g; LCD_DC_DATA; send_data(data); } /** * @brief Set the bus in read mode * * @param[in] g The GDisplay structure * * @notapi */ static inline void setreadmode(GDisplay *g) { (void) g; } /** * @brief Set the bus back into write mode * * @param[in] g The GDisplay structure * * @notapi */ static inline void setwritemode(GDisplay *g) { (void) g; } /** * @brief Read data from the lcd. * @return The data from the lcd * * @param[in] g The GDisplay structure * * @notapi */ static inline gU16 read_data(GDisplay *g) { (void) g; return 0; } #endif /* _GDISP_LLD_BOARD_H */
inmarket Posted December 6, 2019 Report Posted December 6, 2019 The problem here is a build problem. GDISP builds in 2 possible modes - single display and multiple display. Which it uses is a complex combination of include paths, variables in gfxconf.h and linking. The build results in quite different code for the two options. If your gdisp_lld_init is not being called it means you have this process wrong. First GDISP_TOTAL_DISPLAYS, GDISP_DRIVER_LIST and GDISP_PIXEL_FORMAT should not be defined at all in your gfxconf.h for a single display. Instead the specific driver directory you want to use should be on your compiler INCLUDE path and the specific driver files should be included in the build. Also, the various _options.h files should not be altered. All your customizations should be in your gfxconf.h file. See the example demo programs and the provided gfx.conf.example file in the top directory. In general look carefully at the provided build files and the wiki if you have any questions.
Arthur O. Posted December 9, 2019 Author Report Posted December 9, 2019 (edited) Hi @inmarket and thank you for the swift reply, I rolled back the changes made to the gdisp_options.h file after posting my message. I followed the wiki using Eclipse at this link and went through the whole process but include paths look like i got everything (see linked image). I used the single file inclusion, do you think i should consider using the makefile approach ? I'm a bit kinky about what ST is doing with its compiler in SW4STM32. Thanks again for your time, Arthur Edited December 9, 2019 by Arthur O.
Arthur O. Posted December 9, 2019 Author Report Posted December 9, 2019 Update : these are the values of the GDISP default variable (which i find really odd and i ca't change them whatsoever, including void* board and void* priv):
inmarket Posted December 9, 2019 Report Posted December 9, 2019 This looks like GDISP is set to some random value in flash. It is certainly not valid. The GDISP variable is not initialised until after the first display driver is initialised so don't expect it to be valid until after that. With regard to eclipse - I don't use it but I know there are many in the community that do. Personally I much prefer the make system - just create a makefile (I can't remember off the top of my head where the master example one is) and it does everything for you.
Arthur O. Posted December 9, 2019 Author Report Posted December 9, 2019 Hi again @inmarket and thanks for taking the time, Thanks for the direction, i'll look into it. I'm not that familiar with makefiles as a whole i'm quite a newbie in C development. Good reason to learn then ! So do you know if the initialized display driver has its own instance of GDisplay type or is it stored in the GDISP variable anyway ? Thank you again cheers, Arthur
Arthur O. Posted December 9, 2019 Author Report Posted December 9, 2019 Oh and is it normal that the GDriver* driverchain returns an unlimited amount of instances ? Cheers
inmarket Posted December 9, 2019 Report Posted December 9, 2019 Each display driver creates a GDisplay object to hold its run-time data. The first display in the system gets assigned to the GDISP pointer. All drivers, of any type, are maintained in a GDriver list. In your case because the init process is not happening correctly GDISP is totally invalid.
Arthur O. Posted December 10, 2019 Author Report Posted December 10, 2019 Hi @inmarket i found the problem ! I didn't define the heap size in gfxconf.h, hence the invalid adressing and values of the GDISP variable. I defined it as 8192 and it woks like a charm ! I suspect i didn't allocate enough stack either to the thread so that's all fixed now. Thanks again for your time and for the library ! Cheers, Arthur
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