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

C Setup with UC1608 on STM32 #179

Closed
ghost opened this issue Feb 4, 2017 · 15 comments
Closed

C Setup with UC1608 on STM32 #179

ghost opened this issue Feb 4, 2017 · 15 comments
Labels

Comments

@ghost
Copy link

ghost commented Feb 4, 2017

Hello,

I was using u8glib (it is really great!) on AVR few years, but now I am working with STM32L1xx. I decided to go with new version (u8g2) with C, not C++. But there is no C Setup example or introduction (only for C++) so I started to implement my code (no Arduino, not a fan).
Basically I wrote SPI communication layer with UC1608 using DMA and all I need is to have working drawing functions to frame buffer, which I will then send to the display (240x120 px, ERC240120FS-1).

Because there is no documentation for u8g2_Setup_uc1608_240x128_f, I was unable to use it. But for drawing functions are only important dimensions of the display, buffer size/address and screen rotation, right?

void u8g2_Setup_uc1608_240x128_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;
uint8_t *buf;
u8g2_SetupDisplay(u8g2, u8x8_d_uc1608_240x128, u8x8_cad_001, byte_cb, gpio_and_delay_cb);
buf = u8g2_m_uc1608_30_f(&tile_buf_height);
u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
 }

The initialization above was rewrited to

static uint8_t buff[3840];
uint8_t *buf;
buf = buff;
u8g2_SetupBuffer(&u8g2Instance, buf, 8, u8g2_ll_hvline_vertical_top_lsb, U8G2_R0);

Then I tried to draw line with u8g2_DrawLine(&u8g2Instance, 30, 30, 60, 60); but nothing happened in the frame buffer. Communication with the display is working.

May I get some help with implementing this library in C without using arduino?

Thank you in advance!

@olikraus
Copy link
Owner

olikraus commented Feb 4, 2017

U8g2 works nicely without C++/Arduino. And yes, it is right, i never found time to document this.

Some startingpoint could be this:
https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform

Then there was a similar question some time back: #117
See there for some answers.

As mentioned, your first step should be a new delay & GPIO procedure. Once you have this procedure, you can at least display something. Further speed improvements can be done, by writing a byte communication procedure.

Taking your setup:

void u8g2_Setup_uc1608_240x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)

First argument is an empty fresh pointer to a u8g2 structure

u8g2_t u8g2;
void u8g2_Setup_uc1608_240x128_f(&u8g2, ...)

Second argument is the rotation callback.
You can use one of the predefined callbacks, e.g. U8G2_R0.

void u8g2_Setup_uc1608_240x128_f(&u8g2, U8G2_R0, ...)

Third argument is the byte procedure. Suggestion is to use one of the existing "bitbanging" procedure. Once your display works, you can decide to replace this by a custom procedure (and add your own DMA support).
But initially i suggest to use u8x8_byte_4wire_sw_spi:

void u8g2_Setup_uc1608_240x128_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, ...)

Finally you need the mentioned delay and GPIO procedure, but i guess this is described in the referenced documents.

Let me know if you have further questions.

@olikraus
Copy link
Owner

olikraus commented Feb 4, 2017

One more point: You do not need to deal with buffers. This is handled by u8g2. The typical setup (taken from the arm project mentioned in #117) looks like this:

  u8g2_Setup_ssd1306_i2c_128x64_noname_2(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_lpc11u3x); // setup internal buffers and structures
  u8g2_InitDisplay(&u8g2);     // transfer init sequence to the display
  u8g2_SetPowerSave(&u8g2, 0);  // turn on display

@olikraus
Copy link
Owner

olikraus commented Feb 4, 2017

I did some updates here also:
https://github.com/olikraus/u8g2/wiki/u8g2setupc

@ghost
Copy link
Author

ghost commented Feb 4, 2017

Thank you very much! This is exactly what I needed to know :)
I defined gpio and delay function as below

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:

			__HAL_RCC_GPIOB_CLK_ENABLE();
			/* SPI SCK, MOSI GPIO pin configuration  */
			GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_5;
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
			GPIO_InitStruct.Pull = GPIO_PULLDOWN;
			GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
			HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

			RST_LCD_GPIO_CLK_ENABLE();
			GPIO_InitStruct.Pin = RST_LCD_PIN;
			GPIO_InitStruct.Pull = GPIO_NOPULL;
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
			HAL_GPIO_Init(RST_LCD_PORT, &GPIO_InitStruct);

			CS_LCD_GPIO_CLK_ENABLE();
			GPIO_InitStruct.Pin = CS_LCD_PIN;
			GPIO_InitStruct.Pull = GPIO_NOPULL;
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
			HAL_GPIO_Init(CS_LCD_PORT, &GPIO_InitStruct);

			CD_LCD_GPIO_CLK_ENABLE();
			GPIO_InitStruct.Pin = CD_LCD_PIN;
			GPIO_InitStruct.Pull = GPIO_NOPULL;
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
			HAL_GPIO_Init(CD_LCD_PORT, &GPIO_InitStruct);
		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_3, SET);
			else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, 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_5, SET);
			else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, RESET);

		break;
		// Function to define the logic level of the CS line
		case U8X8_MSG_GPIO_CS:
			if (arg_int) HAL_GPIO_WritePin(CS_LCD_PORT, CS_LCD_PIN, SET);
			else HAL_GPIO_WritePin(CS_LCD_PORT, CS_LCD_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(CD_LCD_PORT, CD_LCD_PIN, SET);
			else HAL_GPIO_WritePin(CD_LCD_PORT, CD_LCD_PIN, RESET);

		break;
		//Function to define the logic level of the RESET line
		case U8X8_MSG_GPIO_RESET:
			if (arg_int) HAL_GPIO_WritePin(RST_LCD_PORT, RST_LCD_PIN, SET);
			else HAL_GPIO_WritePin(RST_LCD_PORT, RST_LCD_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.
}

but I had small problem with defining buffer for full frame. Default function is

uint8_t *u8g2_m_uc1608_30_f(uint8_t *page_cnt)
{
  static uint8_t buf[1920];
  *page_cnt = 8;
  return buf;
}

but with static array declaration it just go crazy and eat all of the RAM memory (I am using System Workbench from ac6 tools) and have no idea why it is doing this. The RAM size is 32 kB and compiler said, that it will need another ~57kB of RAM.

So I declared the buf[1920] as global variable in the main.c and it works now (allocate only 1920 bytes).
But there is small problem - I can draw only on one half of the display (240x64). Doubling the frame buffer to 3840 doesn't help.

u8g2_DrawLine(&disp, 120, 0, 120, 120);
u8g2_SendBuffer(&disp);

Is there some kind of limitation (for example drawing on two halfs of the display) or did I missed something?

@olikraus
Copy link
Owner

olikraus commented Feb 4, 2017

Remarks:

  • U8X8_MSG_DELAY_10MICRO and U8X8_MSG_DELAY_100NANO also get the number of 10us and 100ns for delay (similar to the milis message). However both messages are not in use at the moment.
  • Making the buffer global is fully valid.
  • If you increase the buffer size, you also have to increase the value for page_cnt. One page contains 8 pixel rows. So 8 pages are 64 rows. Basically the page_cnt will tell u8g2 the size of the buffer.

@ghost
Copy link
Author

ghost commented Feb 6, 2017

Thank you! I successfully managed to implement these changes and everything works great!

@ghost
Copy link

ghost commented Jun 23, 2018

Hi! I've been trying to use u8g2 lib with my STM32 and i can't do it work.
I configure all pheriphericals and delays with function:
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) as anubisis.
I want to comunicate to my display (EA DOGXL160) with SPI protocole but i've rewrite code to:

uint8_t u8x8_byte_4wire_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  uint8_t b;
  uint8_t *data;

  switch(msg)
  {
    case U8X8_MSG_BYTE_SEND:
      data = (uint8_t *)arg_ptr;
      while( arg_int > 0 )
      {
    	  b = *data;
    	  data++;
    	  arg_int--;
    	  HAL_SPI_Transmit(&hspi1,&b,1,100);
      }
      break;

    case U8X8_MSG_BYTE_SET_DC:
    	if(arg_int == 0){
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
    	}
    	if(arg_int == 1){
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
    	}
      break;

    case U8X8_MSG_BYTE_START_TRANSFER:
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
    	asm("NOP");
      break;

    case U8X8_MSG_BYTE_END_TRANSFER:
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
    	asm("NOP");
    default:
      return 0;
  }
  return 1;
}

In the main(), i've configured the display as you explain in the the wiki, using:

u8g2_Setup_uc1610_ea_dogxl160_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi,u8g2_gpio_and_delay_stm32);
  u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
  u8g2_SetPowerSave(&u8g2, 0); // wake up display

Finally in the loop, i've tryed to draw a line with the code,

u8g2_DrawLine(&u8g2, 120, 0, 120, 120);
 u8g2_SendBuffer(&u8g2);

but it doesnt print nothing in the display, help please

@olikraus
Copy link
Owner

Is CS connected to Pin 6? If yes, shouldn't it be inverted?

@ghost
Copy link

ghost commented Jun 24, 2018

Yes, i was inverted. Now i've solved this problem but when I try to draw something, the display prints it
so slow, i mean, by lines. And refreshing the hole display takes 5 sec
The code i'm implementing is:

	 u8g2_ClearBuffer(&u8g2);
	 u8g2_SetFont(&u8g2,u8g2_font_logisoso58_tn);
	 u8g2_DrawStr(&u8g2, -5, 70, "100");
	 u8g2_SendBuffer(&u8g2);

@olikraus
Copy link
Owner

U8g2 itself is optimized for speed, but you may change your interface code:

    case U8X8_MSG_BYTE_SEND:
      data = (uint8_t *)arg_ptr;
      while( arg_int > 0 )
      {
    	  b = *data;
    	  data++;
    	  arg_int--;
    	  HAL_SPI_Transmit(&hspi1,&b,1,100);
      }
      break;

Instead i think the following should be faster:

    case U8X8_MSG_BYTE_SEND:
      HAL_SPI_Transmit(&hspi1,arg_ptr,arg_int,100);
      break;

Additionally I saw same user posts that HAL_SPI_Transmit for STM32 is slow. But because I do not know anything on the HAL_SPI_Transmit I can not support here.

@ghost
Copy link

ghost commented Jun 24, 2018

Ok, got it!!! Thanks!!!!
Great library.

@nikola-v
Copy link

Hi,
trying to make my st7920 128x64 display run reading through other people solutions made me think we should set repo for running examples which could help us all.
If somebody can help out with my problem (it just doesn't display anthing) and share his config I would gladly go through various development boards and create examples for it.

I have put code on: https://github.com/nikola-v/u8g2_template_stm32f103c8t6

@olikraus
Copy link
Owner

I have added your project to the STM related U8g2 links: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform#stm32

@EEJerry
Copy link

EEJerry commented Aug 10, 2023

Hi @olikraus , @ghost I also use LCD 240x120 uc1608 with STM32, I'm getting an error that can't be displayed. can you help me to deal with them.

@olikraus
Copy link
Owner

The request from EEJerry is discussed here: #2240

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

No branches or pull requests

3 participants