Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use U8g2 with STM32 #356

Closed
ghost opened this issue Sep 12, 2017 · 22 comments
Closed

Use U8g2 with STM32 #356

ghost opened this issue Sep 12, 2017 · 22 comments

Comments

@ghost
Copy link

ghost commented Sep 12, 2017

Hi,
U8g2 is the great library for LCD and i want to use it with my stm32f4 board. I was use LCD with ST7920 chip. I done the setup for my stm with #179 and u8g2setupc. But the LCD keeping show some strange characters.
capture
I'm new to stm and u8g2. So many thanks for helps.
Here my config

PA1 - CLK - E
PA2 - SPI data - R/W
PA3 - RST - RST
PA4 - CS - PSB
PA5 - CD - RS

u8g2_Setup_st7920_s_128x64_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8g2_gpio_and_delay_stm32);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);

void draw(u8g2_t *u8g2)
{
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFontDirection(u8g2, 0);
u8g2_SetFont(u8g2, u8g2_font_6x12_tr);
u8g2_DrawStr(u8g2, 0, 20, "Hello World");
}

u8g2_FirstPage(&u8g2);
do
{
draw(&u8g2);
} while( u8g2_NextPage(&u8g2) );

uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg,U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
switch(msg){
//Initialize SPI peripheral
case U8X8_MSG_GPIO_AND_DELAY_INIT:
break;
//Function which implements a delay, arg_int contains the amount of ms
case U8X8_MSG_DELAY_MILLI:
HAL_Delay(arg_int);
break;
//Function to define the logic level of the clockline
case U8X8_MSG_GPIO_SPI_CLOCK:
if (arg_int) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
break;
//Function to define the logic level of the data line to the display
case U8X8_MSG_GPIO_SPI_DATA:
if (arg_int) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
break;
// Function to define the logic level of the CS line
case U8X8_MSG_GPIO_CS:
if (arg_int) HAL_GPIO_WritePin(GPIOA, CS_LCD_Pin, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, CS_LCD_Pin, GPIO_PIN_RESET);
break;
//Function to define the logic level of the Data/ Command line
case U8X8_MSG_GPIO_DC:
if (arg_int) HAL_GPIO_WritePin(GPIOA, CD_LCD_Pin, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, CD_LCD_Pin, GPIO_PIN_RESET);
break;
//Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
if (arg_int) HAL_GPIO_WritePin(GPIOA, RST_LCD_Pin, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, RST_LCD_Pin, GPIO_PIN_RESET);
break;
default:
return 0; //A message was received which is not implemented, return 0 to indicate an error
}
return 1; // command processed successfully.
}

@olikraus
Copy link
Owner

@ghost
Copy link
Author

ghost commented Sep 12, 2017

Many thanks to you olikraus
I just already checked the wires and added some delay functions (us, ns) .
Follows:
https://github.com/olikraus/u8g2/issues/179
https://github.com/olikraus/u8g2/wiki/setup_tutorial
https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform.
So my LCD works perfectly.
capture
I think people who new to stm32 and u8g2 like me can follow three reference materials above. So you can close this issue. Thankyou! ^^

@olikraus
Copy link
Owner

:)

@Kinvy66
Copy link

Kinvy66 commented Oct 10, 2017

I use OLED(SSD1306 12864), can you send your whole project to me for reference? thank you!my email:
1032791224@qq.com

@rokk0
Copy link

rokk0 commented Nov 5, 2017

Is there any detailed tutorial how to use ST7920 and STM32 with u8g2? I was trying to use these "issue-guides", but when I call: u8g2_Setup_st7920_s_128x64_1(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8g2_gpio_and_delay_stm32); - I'm out of RAM. Old version (u8glib) works fine, but I need UTF-8 fonts from new version.

Without calling setup function:
Program Size: Code=9844 RO-data=228 RW-data=28 ZI-data=2020

With it:
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching u8g2_d_memory.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching startup_stm32f030x8.o(STACK).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching tim.o(.bss).
projectl.axf: Error: L6406E: No space in execution regions with .ANY selector matching spi.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching adc.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching main.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching i2c.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching main.o(.data).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching u8x8_cad.o(.bss).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching system_stm32f0xx.o(.data).
project.axf: Error: L6406E: No space in execution regions with .ANY selector matching stm32f0xx_hal.o(.data).
project.axf: Error: L6407E: Sections of aggregate size 0x17ef8 bytes could not fit into .ANY selector(s).
Not enough information to list image symbols.
Not enough information to list the image map.

@olikraus
Copy link
Owner

olikraus commented Nov 5, 2017

maybe you did not activate the gcc linker garbage collector.

@rokk0
Copy link

rokk0 commented Nov 5, 2017

I was trying to add --gc-sections in Linker parameters, but got this error:
project.axf: error: L3900U: Unrecognized option '--gc-sections'.

@olikraus
Copy link
Owner

olikraus commented Nov 5, 2017

Usually options are:
compiler: -ffunction-sections -fdata-sections
linker: -Wl,--gc-sections

@rokk0
Copy link

rokk0 commented Nov 5, 2017

Looks like I cannot enable garbage collection in Keil5 linker...

@rokk0
Copy link

rokk0 commented Nov 5, 2017

Keil uses ARM Compiler Toolchain and it has option --remove, that works the same as --gc-sections, but it changed nothing :(

12.118 --remove, --no_remove

Enables or disables the removal of unused input sections from the image.
Usage
An input section is considered used if it contains an entry point, or if it is referred to from a used section.
By default, unused section elimination is disabled when building dynamically linked libraries (DLLs) or shared objects, Use --remove to re-enable unused section elimination.
Use --no_remove when debugging to retain all input sections in the final image even if they are unused.
Use --remove with the --keep option to retain specific sections in a normal build.

@rokk0
Copy link

rokk0 commented Nov 6, 2017

Main problem were static uint8_t buf[x] variables in u8g2_d_memory.c. I commented out all of them and created a global one in that file. Here is step by step guide how to run ST7920 with STM32 in Keil 5 using HAL:

  1. Add all files from u8g2/csrc folder to your project
  2. Include u8g2.h in main.c and create global variable "u8g2_t u8g2;"
  3. Add function for HAL HW SPI usage:
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  uint8_t byte;
  uint8_t *data;
 
  switch(msg)
  {
    case U8X8_MSG_BYTE_SEND:
      data = (uint8_t *)arg_ptr;
      while( arg_int > 0 )
      {
        byte = *data;
        data++;
        arg_int--;
        HAL_SPI_Transmit(&hspi1, &byte, 1, 100);
      }
      break;
    case U8X8_MSG_BYTE_START_TRANSFER:
      HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
      __nop(); // 21 ns
      break;
    case U8X8_MSG_BYTE_END_TRANSFER:
      __nop(); // 21 ns
      HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
      break;
    default:
      return 0;
  }
  return 1;
}
  1. Add gpio_and_delay function (we can leave it "empty" because all required calls to it are from u8x8_byte_4wire_sw_spi function, which one we don't use):
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg,U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
  return 1; // command processed successfully.
}
  1. Add draw function:
void draw(u8g2_t *u8g2)
{
  u8g2_ClearBuffer(u8g2);

  u8g2_SetFontMode(u8g2, 1);
  u8g2_SetFontDirection(u8g2, 0);
  u8g2_SetFont(u8g2, u8g2_font_6x10);

  sprintf(string_1, "LCD refresh: %d ms", lcd_refresh_time);
  u8g2_DrawStr(u8g2, 2, 10, string_1);

  u8g2_SendBuffer(u8g2);
}
  1. Init u8g2 in main function:
u8g2_Setup_st7920_s_128x64_f(&u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8g2_gpio_and_delay_stm32);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
  1. Call draw function in main loop: draw(&u8g2);

@LuizRoque
Copy link

Hi rokk0, I've try to follow the steps you've described, but still i'm not be able to write nothing!, i'm using STM32F070-nucleo board,

here is my code

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "u8g2.h"
#include "spi.h"

// LCD 128x64
u8g2_t u8g2;

uint8_t count = 0;

GPIO_InitTypeDef GPIO_InitStruct;

uint8_t lcd_refresh_time = 1;
char string_1[30];

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void Error_Handler(void);
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr);
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

/* Private functions ---------------------------------------------------------*/

/**

HAL_Init();

/* Configure LED2 /
BSP_LED_Init(LED2);
/
Configure the system clock to 48 MHz */
SystemClock_Config();

  __HAL_RCC_GPIOB_CLK_ENABLE();
/* SPI SCK, MOSI GPIO pin configuration  */
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

//RST_LCD_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

//CS_LCD_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


MX_SPI2_Init();

u8g2_Setup_st7920_128x64_f(&u8g2, U8G2_R0,
u8x8_byte_4wire_hw_spi, u8g2_gpio_and_delay_stm32); // init u8g2 structure

u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0); // wake up display

HAL_Delay(100);

u8g2_ClearDisplay(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_6x10_tr);
u8g2_SetFontMode(&u8g2, 1);
u8g2_SetFontDirection(&u8g2, 0);

//u8g2_ClearBuffer(&u8g2);
//u8g2_DrawUTF8(&u8g2, 0, 40, "Hello world!");
//u8g2_SendBuffer(&u8g2);

/* Infinite loop */
while (1)
{
u8g2_ClearBuffer(&u8g2);

    u8g2_SetFontMode(&u8g2, 1);
    u8g2_SetFontDirection(&u8g2, 0);
    u8g2_SetFont(&u8g2, u8g2_font_6x10_tf);

    //sprintf(string_1, "LCD refresh: %d ms", lcd_refresh_time);
    u8g2_DrawStr(&u8g2, 2, 24, "hello world");

    u8g2_SendBuffer(&u8g2);

    BSP_LED_Off(LED2);
    HAL_Delay(1000);

}
}

uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{

switch(msg){


	//Function which implements a delay, arg_int contains the amount of ms
	case U8X8_MSG_GPIO_AND_DELAY_INIT:


	break;
	//Function which implements a delay, arg_int contains the amount of ms
	case U8X8_MSG_DELAY_MILLI:
		HAL_Delay(arg_int);


	break;
	//Function which delays 10us
	case U8X8_MSG_DELAY_10MICRO:
		for (uint16_t n = 0; n < 320; n++)
		{
			__NOP();
		}

	break;
	//Function which delays 100ns
	case U8X8_MSG_DELAY_100NANO:
		__NOP();

	break;
	//Function to define the logic level of the clockline
	case U8X8_MSG_GPIO_SPI_CLOCK:
		//if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
		//else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);

	break;
	//Function to define the logic level of the data line to the display
	case U8X8_MSG_GPIO_SPI_DATA:
		//if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
		//else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
		BSP_LED_Toggle(LED2);

	break;

	// Function to define the logic level of the CS line
	case U8X8_MSG_GPIO_CS1:
		//if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
		//else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);

	break;
	//Function to define the logic level of the Data/ Command line
	case U8X8_MSG_GPIO_DC:
		//if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
		//else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);

	break;
	//Function to define the logic level of the RESET line
	case U8X8_MSG_GPIO_RESET:
		//if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
		//else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);

	break;
	default:
		return 0; //A message was received which is not implemented, return 0 to indicate an error
}

return 1; // command processed successfully.

}

uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t byte;
uint8_t *data;

switch(msg)
{
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;
while( arg_int > 0 )
{
byte = *data;
data++;
arg_int--;
HAL_SPI_Transmit(&hspi2, &byte, 1, 100);
}
BSP_LED_Toggle(LED2);

  break;
case U8X8_MSG_BYTE_START_TRANSFER:
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
  __NOP(); // 21 ns

  break;
case U8X8_MSG_BYTE_END_TRANSFER:
  __NOP(); // 21 ns
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
  __NOP();
  break;

case U8X8_MSG_BYTE_SET_DC:
	if (arg_int) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);

	break;

default:
  return 0;

}
return 1;
}

/**

  • @brief This function is executed in case of error occurrence.
  • @param None
  • @RetVal None
    /
    static void Error_Handler(void)
    {
    while(1)
    {
    /
    Turn LED2 on */
    BSP_LED_Toggle(LED2);
    HAL_Delay(1000);
    }
    }

/**

  • @brief System Clock Configuration
  •     The system Clock is configured as follow : 
    
  •        System Clock source            = PLL (HSI)
    
  •        SYSCLK(Hz)                     = 48000000
    
  •        HCLK(Hz)                       = 48000000
    
  •        AHB Prescaler                  = 1
    
  •        APB1 Prescaler                 = 1
    
  •        HSI Frequency(Hz)              = 8000000
    
  •        PREDIV                         = 2
    
  •        PLLMUL                         = 12
    
  •        Flash Latency(WS)              = 1
    
  • @param None
  • @RetVal None
    */
    void SystemClock_Config(void)
    {
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;

/* No HSE Oscillator on Nucleo, Activate PLL with HSI as source /
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_NONE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)
{
/
Initialization Error */
while(1);
}

/* Select PLL as system clock source and configure the HCLK, PCLK1 clocks dividers /
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1)!= HAL_OK)
{
/
Initialization Error */
while(1);
}
}

Can you give a little help?

@rokk0
Copy link

rokk0 commented Nov 24, 2017

I think you need to call u8g2_Setup_st7920_s_128x64_f, not u8g2_Setup_st7920_128x64_f.

@breezer15
Copy link

breezer15 commented Dec 5, 2017

Hello,

i want to use u8g2 with a STM32L432 via hardware SPI and a SH1106 OLED Display. I used the instruction from rokk0 to implement the code, but the Display shows nothing.

Can anyone help?

Here are the important functions:

uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t byte;
uint8_t *data;

switch(msg)
{
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;
while( arg_int > 0 )
{
byte = *data;
data++;
arg_int--;
HAL_SPI_Transmit(&hspi1, &byte, 1, 100);
}
break;
case U8X8_MSG_BYTE_SET_DC:
if(arg_int == 0){HAL_GPIO_WritePin(
DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET);
}
if(arg_int == 1){HAL_GPIO_WritePin(
DC_GPIO_Port, DC_Pin, GPIO_PIN_SET);
}
break;
case U8X8_MSG_BYTE_START_TRANSFER:
HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
asm("NOP");
break;
case U8X8_MSG_BYTE_END_TRANSFER:
asm("NOP");
HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
break;
default:
return 0;
}
return 1;
}

uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg,U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
return 1; // command processed successfully.
}

void draw(u8g2_t *u8g2)
{
u8g2_ClearBuffer(u8g2);

u8g2_SetFontMode(u8g2, 1);
u8g2_SetFontDirection(u8g2, 0);
u8g2_SetFont(u8g2, u8x8_font_chroma48medium8_r);

sprintf(string_1, "LCD refresh: %d ms", lcd_refresh_time);
u8g2_DrawStr(u8g2, 2, 10, string_1);

u8g2_SendBuffer(u8g2);
}

Setup in the Main function:

` __HAL_SPI_ENABLE(&hspi1);

u8g2_Setup_sh1106_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8g2_gpio_and_delay_stm32);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);`

Periodical call of "draw(&u8g2);" in the loop

@LuizRoque
Copy link

Hi, breezer15

All your code seen ok to me, my display has the ks0108 controller, but using his setup didn't work. It just worked using the

u8g2_Setup_st7920_s_128x64_f(&u8g2, U8G2_R0,
u8x8_byte_4wire_hw_spi, u8g2_gpio_and_delay_stm32);

Now is all working!

@thihakyawjob
Copy link

thihakyawjob commented Nov 24, 2018

Hi,

I follow your instruction using Nucleo-F746ZG. My setup is as follow.
PA5 - SCK to ST7920 Pin - E
PA7 - MOSI to ST7920 - RW
PD14 - CS

I would like to know the following information from you.

  1. What is the SPI configuration? SPI Clock, CPOL and CPHA setting? SPI_Datasize? 8Bit or 16Bits.
  2. I attached my file for your review.

Please help me check. I don't know what wrong with it.

Thanks.

Regards,
Thiha
main.txt

@olikraus
Copy link
Owner

Probably I can not support here as library author. I do not what HAL_SPI_Transmit does.

@thihakyawjob
Copy link

thihakyawjob commented Nov 25, 2018 via email

@thihakyawjob
Copy link

Dear Olikraus,

ST7920 LCD doesn't show properly. I don't know what is wrong. Please give me some suggestion.

img_0192

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f7xx_hal.h"

/* USER CODE BEGIN Includes /
#include "u8g2.h"
/
USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN PV /
/
Private variables ---------------------------------------------------------/
u8g2_t u8g2;
/
USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);

/* USER CODE BEGIN PFP /
/
Private function prototypes -----------------------------------------------*/
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg,U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr);
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
void draw(u8g2_t u8g2);
/
USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**

  • @brief The application entry point.
  • @RetVal None
    /
    int main(void)
    {
    /
    USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration----------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals /
MX_GPIO_Init();
MX_SPI1_Init();
/
USER CODE BEGIN 2 */

u8g2_Setup_st7920_s_128x64_f(&u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8g2_gpio_and_delay_stm32);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);

/* USER CODE END 2 */

/* Infinite loop /
/
USER CODE BEGIN WHILE */
while (1)
{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
draw(&u8g2);
HAL_Delay(1000);

}
/* USER CODE END 3 */

}

/**

  • @brief System Clock Configuration
  • @RetVal None
    */
    void SystemClock_Config(void)
    {

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

/**Configure the main internal regulator output voltage 
*/

__HAL_RCC_PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

/**Initializes the CPU, AHB and APB busses clocks 
*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 100;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}

/**Activate the Over-Drive mode 
*/

if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
_Error_Handler(FILE, LINE);
}

/**Initializes the CPU, AHB and APB busses clocks 
*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}

/**Configure the Systick interrupt time 
*/

HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

/**Configure the Systick 
*/

HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, LCD_CS_Pin|LCD_DC_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin : LCD_RST_Pin */
GPIO_InitStruct.Pin = LCD_RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LCD_RST_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : LCD_CS_Pin */
GPIO_InitStruct.Pin = LCD_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LCD_CS_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : LCD_DC_Pin */
GPIO_InitStruct.Pin = LCD_DC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LCD_DC_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

////////////////////// FOR HW SPI /////////////////////////////////////
uint8_t byte;
uint8_t *data;
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{

switch(msg)
{
case U8X8_MSG_BYTE_SEND:
// data = (uint8_t *)arg_ptr;
// while( arg_int > 0 )
// {
// byte = *data;
// HAL_SPI_Transmit(&hspi1, &byte, 1, 100);
// data++;
// arg_int--;
//
// }
HAL_SPI_Transmit(&hspi1, arg_ptr, arg_int, 100);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
__nop(); // 21 ns
break;
case U8X8_MSG_BYTE_END_TRANSFER:
__nop(); // 21 ns
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
break;
default:
return 0;
}
return 1;
}

uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg,U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
return 1; // command processed successfully.
}

void draw(u8g2_t *u8g2)
{
u8g2_ClearBuffer(u8g2);

// u8g2_SetFontMode(u8g2, 1);
// u8g2_SetFontDirection(u8g2, 0);
u8g2_SetFont(u8g2, u8g2_font_6x10_tf);

// sprintf(string_1, "LCD refresh: %d ms", 100);
u8g2_DrawStr(u8g2, 10, 70, "100");

u8g2_SendBuffer(u8g2);
}
/* USER CODE END 4 */

/**

  • @brief This function is executed in case of error occurrence.
  • @param file: The file name as string.
  • @param line: The line in file as a number.
  • @RetVal None
    */
    void _Error_Handler(char file, int line)
    {
    /
    USER CODE BEGIN Error_Handler_Debug /
    /
    User can add his own implementation to report the HAL error return state /
    while(1)
    {
    }
    /
    USER CODE END Error_Handler_Debug */
    }

#ifdef USE_FULL_ASSERT
/**

  • @brief Reports the name of the source file and the source line number
  •     where the assert_param error has occurred.
    
  • @param file: pointer to the source file name
  • @param line: assert_param error line source number
  • @RetVal None
    /
    void assert_failed(uint8_t
    file, uint32_t line)
    {
    /* USER CODE BEGIN 6 /
    /
    User can add his own implementation to report the file name and line number,
    tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) /
    /
    USER CODE END 6 /
    }
    #endif /
    USE_FULL_ASSERT */

/**

  • @}
    */

/**

  • @}
    */

/************************ (C) COPYRIGHT STMicroelectronics *END OF FILE/

@olikraus
Copy link
Owner

I do not know the STM32 specific API nor did I wrote the code (additionally you didn't use proper code tags here). Moreover I do not have time to debug this. If you did not wrote the glue code between u8g2 and STM32, then maybe try to find the person who wrote this code.

I can only check the hardware with you (wiring, signal levels) with you. Did you add proper signal level converters here?

@thihakyawjob
Copy link

Dear Olikraus,

I change the following and it is working now. I don't need the level shifter as well. Thanks.

void u8g2_Setup_st7920_s_128x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{
uint8_t tile_buf_height = 8;
//uint8_t *buf;
uint8_t buf[2048];
u8g2_SetupDisplay(u8g2, u8x8_d_st7920_128x64, u8x8_cad_st7920_spi, byte_cb, gpio_and_delay_cb);
//buf = u8g2_m_16_8_f(&tile_buf_height);
u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_horizontal_right_lsb, rotation);
}

@iamsaber
Copy link

iamsaber commented Jul 1, 2019

Main problem were static uint8_t buf[x] variables in u8g2_d_memory.c. I commented out all of them and created a global one in that file.

Hi rokko,
Can you explain this part a little more please? how and in which file you create a global variable instead ? can you put here this part of your code ? and also tell us if you change "u8g2_Setup_st7920_s_128x64_f" function declaration in the library also or not?

Thanks alot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants