Display Screens I2C Modules Sensor/Module Interfacing Sensors and Modules Tech

In previous blog we covered a brief overview of how the OLED display works in microscopic level and also understood various types of OLED displays available in the market . In this blog we’ll be discussing  how to configure the SSD1306  display with the microcontroller and we’ll be  making the embedded driver as well.128×64 display is a dot matrix display , hence 128×64 =8192 total pixels . It is by turning on/off these pixels we display graphical image of any shape . It is the current provided to each pixel that varies the brightness.

HARDWARE DESCRIPTION

OLED Display chosen is driven by SSD1306 Driver IC although they are other ICs such as SSD1331 which can be used to drive the display . These ICs  are CMOS OLED Driver controller for dot-matrix system . OLED has 256 brightness steps .Besides 128×64 , 128×32 display resolution is also available.

Specification of ssd1306 128×64 OLED

Display Structure

OLED DISPLAY is mapped using GDDRAM page structure  OF SSD1306

GDDRAM or graphic display ram is a bit mapped static RAM . It holds the bit pattern to be displayed. The GDDRAM having size 128×64 is divided into 8 pages from PAGE 0 TO PAGE 7 which is used for monochrome matrix display . When data bit D0 – D7 is sent the row0 gets filled with D0 and D7 is written into the bottom row.

ADDRESSING MODE

Hardware Pinout

ALGORITHM

  • Select the I2C slave address and specify the operation that will be performed i.e Read 0x79 or Write 0x78. 
				
					

           #define SSD1306_I2C_ADDR         0x78

				
			
  • Set the clock divide ratio and oscillator frequency . Bit 3-0 sets the clock divide ratio , Bit 7-4 sets the oscillator frequency
				
					SSD1306_WRITECOMMAND(0xD5); //--set display clock divide ratio/oscillator                frequency
	SSD1306_WRITECOMMAND(0xF0); //--set divide ratio


				
			
  • Set the multiplex ratio switching to any value ranging from 16-63
				
					

         SSD1306_WRITECOMMAND(0xA8); //--set multiplex ratio(1 to 64)

				
			
  • Display start line addressing in which the starting address of the display ram is determined . In our case this is set to zero and RAM row 0 is mapped to col 0
				
					

          SSD1306_WRITECOMMAND(0x40); //--set start line address

				
			
  • Set memory addressing mode using page addressing mode, horizontal addressing mode, vertical addressing mode.
				
					

          SSD1306_WRITECOMMAND(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	SSD1306_WRITECOMMAND(0xB0); //Set Page Start Address for Page Addressing Mode,0-7

				
			

Set column address using a triple byte first specifies the column setting , second column start and third column  end . Do the same for the page

				
					

  SSD1306_WRITECOMMAND(0x00); //---set low column address
	SSD1306_WRITECOMMAND(0x10); //---set high column address

				
			
  • Set pre-charge period and VCOMH deselect level 
				
					

  SSD1306_WRITECOMMAND(0xDB); //--set vcomh

				
			
  • Entire display is on using A4H and A5H command
				
					SSD1306_WRITECOMMAND(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
				
			
  • The normal functionality of the display is set rather than inverted
				
					SSD1306_WRITECOMMAND(0xA6); //--set normal display

				
			

FUNCTIONAL IMPLEMENTATION OF OLED SSD1306 DISPLAY

The I2C devices are recognized by their slave addresses and the format of their address is as follows 

SA0 – Provides 2 slave address option to choose from

R/W bit – This bit is to specify the I2C read or write of the operation 1 for read operation 0 for write operation .

For write the I2C address is as follows 0x78

For read the I2C address is as follows 0x79

This function is used to set the X and Y coordinates of display and specifies the point where data is to be displayed .

The function takes in 2 16 bit arguments which are then passed into the variable of the structure SSD1306 , CurrentX and CurrentY

This char type function takes in the pointer of the string , font of the string or char to be displayed and the color of the LCD which is a enumeration having 2 values white and black

This function pushes character by character using the function Putc until the last character is reached and returns the string in the end 

Also font in which the text is to be displayed is chosen using the font.c library

This char type function takes in 3 arguments the character of the input string , the font from fonts.c library and the color of the OLED

The function checks if there is space available on the pixel on which the user wants put the data and returns error in case of a collision

Next the size of the font chosen is determined and using the draw pixel function both the X and Y coordinates are updated and in the end the pointer is updated to go through the next character and the previous character is returned.

The Draw pixel function takes in 2, 16 bit X, Y values as arguments .

Next the function checks if the entered values are greater than the width and height of the OLED. The function also checks if the pixels are inverted .

Next the X and Y location are put in the SSD1306_buffer which is a static function

In this function the SSD1306 is initialized using various parameters . The write command for opening the display is sent , next the memory addressing mode is set following which the addressing mode horizontal , vertical , page is set . Next the page start address is set , scan direction of the COM output is set , the start line address is also specified , the remapping of the segment is mapped to 0-127, next the clock divide ratio is set and finally SSD1306 is turned on.

 

This function is used write data to a single device with the address being defined . The register to which data is to be written is specified and is transmitted using HAL_I2C_Master_Transmit(&hi2c1, address, dt, 2, 10); function

This function is used to write multiple slave devices and the count is updated every time the next device is to be selected.

This function is used to draw a line on the display , which initially checks if overflow condition is reached or not, next after displaying the dot on every pixel the X , Y coordinates are updated after checking if the line is a horizontal line or vertical line and the iteration is done until the coordinate X1 , Y1 is reached 

This function is used to draw a rectangle on the display using the starting position as mentioned in X , Y coordinates and width w and height h . Using these 4 variables the draw line function is called 4 times .

This function is used to draw triangle using the drawline function and calling it each time for starting and ending coordinates of the line which are (x1, y1), (x2,y2) and (x3, y3) .

This function takes in input x0 , y0 as the starting coordinates of the circle and after calling the draw pixel function and using the radius as the argument the circle is drawn.

CUBE IDE CONFIGURATION

CODE 

To display the score of a game

				
					#include "main.h"
#include "fonts.h"
#include "ssd1306.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;/STEP 1/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
\  * @brief  The application entry point.
  * @retval int
  */
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_I2C1_Init();/STEP 2/
  /* USER CODE BEGIN 2 */
  SSD1306_Init();/STEP 3/
    char snum[5];


    SSD1306_GotoXY (35,0);/STEP 4/
    SSD1306_Puts ("SCORE", &Font_11x18, 1);/STEP 5/

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  for ( int x = 1; x <= 10000 ; x++ )/STEP 6/
	  	{
	  		itoa(x, snum, 10);
	  		SSD1306_GotoXY (0, 30);
	  		SSD1306_Puts ("             ", &Font_16x26, 1);
	  		SSD1306_UpdateScreen();
	  		if(x < 10) {
	  			SSD1306_GotoXY (53, 30);  // 1 DIGIT
	  		}
	  		else if (x < 100 ) {
	  			SSD1306_GotoXY (45, 30);  // 2 DIGITS
	  		}
	  		else if (x < 1000 ) {
	  			SSD1306_GotoXY (37, 30);  // 3 DIGITS
	  		}
	  		else {
	  			SSD1306_GotoXY (30, 30);  // 4 DIGIS
	  		}
	  		SSD1306_Puts (snum, &Font_16x26, 1);
	  		SSD1306_UpdateScreen();
	  		HAL_Delay (500);
	  	    }
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 400000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

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

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

				
			

CODE EXPLANATION

Kunal Gupta
Author: Kunal Gupta

Author

Kunal Gupta

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog