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 */