Interface SSD1306 OLED display with STM32
I already covered how to interface LCD 16×2 using I2C with STM32 and how to interface 1.3″ SH1106 oled display with STM32. Today I have another Oled display with me, It is a 0.96″ SSD1306 OLED display and we will interface it using I2C.
- This display uses the I2C protocol to communicate to the microcontroller. So here you need only 2 pins i.e. SDA and SCL from the microcontroller and the VCC and GND.
- I am using STM32f103c8t6 but the code will remain the same for all STM32 devices.
- I searched a lot for the libraries but all I could find were that of arduino. Than at last I found one by Alexander Lutsai, and I modified it so that it can be used with the STM32 CubeMx
CubeMX Configuration
Below is the image showing the I2C configuration.
- Set the I2C in the FAST MODE, as it is required for the OLED Display
- The SCL and SDA Pins will get automatically selected.
The Connection is as shown Below
As shown in the image above:
- The display is powered with 3.3V from the STM32 board itself.
- The SCL and SDA pins are connected to their respective counterparts on the board.
The Code
Open the ssd1306.c and change the I2C handler according to your setup.
extern I2C_HandleTypeDef hi2c1;
#define SSD1306_I2C &hi2c1
Also configure the display resolution in the ssd1306.h file.
/* SSD1306 width in pixels */
#ifndef SSD1306_WIDTH
#define SSD1306_WIDTH 128
#endif
/* SSD1306 LCD height in pixels */
#ifndef SSD1306_HEIGHT
#define SSD1306_HEIGHT 64
#endif
You can see the functions available in the functions tab under ssd1306.c or in the ssd1306.h file.
Print simple strings
#include "ssd1306.h"
#include "fonts.h"
int main()
{
.....
SSD1306_Init (); // initialise the display
SSD1306_GotoXY (10,10); // goto 10, 10
SSD1306_Puts ("HELLO", &Font_11x18, 1); // print Hello
SSD1306_GotoXY (10, 30);
SSD1306_Puts ("WORLD !!", &Font_11x18, 1);
SSD1306_UpdateScreen(); // update screen
while (1) { }
}
- Here we will first initialise the display in the main function.
- Then set the cursor at x=10, y=10 and print “HELLO” at this location.
- Set the cursor at x=10, y=30 and print “WORLD !!” at this location.
- We need to call the function SSD1306_UpdateScreen to update the display with the modified content.
Below is the image showing the output of the above code.
Print Numbers
Any display does not support printing the numbers directly on it. Instead we need to change the number into the equivalent Ascii characters and then print it.
Below the code shows how to print integer and floats.
#include "ssd1306.h"
#include "fonts.h"
#include "stdio.h" // for sprintf
int main()
{
.....
int num = 123456; float flt = 123.45;
char bufnum[7]; char bufflt[7];
SSD1306_Init (); // initialise the display
sprintf (bufnum, "%d", num);
sprintf (bufflt, "%.2f", flt);
SSD1306_GotoXY (10,10); // goto 10, 10
SSD1306_Puts (bufnum, &Font_11x18, 1); // print Hello
SSD1306_GotoXY (10, 30);
SSD1306_Puts (bufflt, &Font_11x18, 1);
SSD1306_UpdateScreen(); // update screen
while (1) { }
}
- Here we will first initialise the display in the main function.
- Then define the character buffers to store the converted integer and float values.
- The sprintf function is used to convert the integer(%d) and float(%f) values to the respective Ascii format.
- Then set the cursor at x=10, y=10 and print num at this location.
- Set the cursor at x=10, y=30 and print flt at this location.
- We need to call the function SSD1306_UpdateScreen to update the display with the modified content.
Below is the image showing the output of the above code.
Bitmaps
We can draw a bitmap image anywhere on the display. We just need to convert the bitmap image to c array format. This tool can do that.
Make sure to choose the configuration as shown below.
Once you click Convert, the c file containing the image array will download. We will copy the array to our project.
#include "ssd1306.h"
#include "fonts.h"
#include "stdio.h" // for sprintf
#include "bitmap.h"
int main()
{
.....
SSD1306_Init();
SSD1306_DrawBitmap(0, 0, logo, 128, 64, 1);
SSD1306_UpdateScreen(); // update screen while (1) { }
}
- Here we will first initialise the display in the main function.
- Then draw the bitmap defined in the bitmap.h file.
- The bitmap start position is set to x=0,y=0.
- The size is 128pixels x 64pixels.
- We need to call the function SSD1306_UpdateScreen to update the display with the modified content.
Below is the image showing the output of the above code.
Scrolling and Animation
The SSD1306 has support for scrolling at hardware level. There are registers in the SSD1306 IC which enable the display to scroll in different directions.
The following are the functions available to do so.
#include "ssd1306.h"
#include "fonts.h"
#include "stdio.h" // for sprintf
#include "bitmap.h"
int main()
{
.....
SSD1306_Init();
SSD1306_DrawBitmap(0, 0, logo, 128, 64, 1);
SSD1306_UpdateScreen(); // update screen
SSD1306_ScrollRight(0x00, 0x07); // scroll entire screen (Page0 to Page7) right
HAL_Delay (5000);
SSD1306_Stopscroll();
SSD1306_ScrollLeft(0x00, 0x07); // scroll entire screen (Page0 to Page7) right
HAL_Delay (5000);
SSD1306_Stopscroll();
while (1) { }
}
In the code above, we are scrolling the entire screen in the right direction for 5 seconds, and then in the left direction for another 5 seconds. The screen contains the bitmap on it and therefore we will see the bitmap scrolling.
The Animation part is explained in the video shown below. Please check out the video to see the complete working.
Hello there, how do I add some new/custom fonts instead of using the inner fonts in library files?
I cannot find where to download the following?? Can you please direct me where to find these files that you mentioned?
”Download the code below, unzip it, Copy the fonts.h, test.h and ssd1306.h in the Inc folder of your project, and fonts.c, test.c and ssd1306.c in the Src folder and open the project now.”
Thank you for very good tutorial. Example runs with minor modification (PB6 & PB7 –> PB8 , PB9) also on NUCLEO-F411RE board and stmcube ide 1.11.0
Would it work in any I2C OLED 128×64 display? and 256×64?
Hi. I am trying to add more fonts. But I did’nt find any program to output 32bit format font archive. Only 8 bit format! Could you tell me wich program did you use? Thanks a lot.
Hi, have you found how to create front ?
Great tutorial and well explained. One small change I made to your SSD1306_DrawBitmap function. You can add “else SSD1306_DrawPixel(x+i, y, 0);” right after the if statement to draw a black pixel instead of white. This will make for a very smooth horse running and eliminates the need to clear the screen following each call to DrawBitmap. Thanks again for the awesome video.
Hello Sir,
Thank you for the tutorial it’s awesome and very helpful, I have just one question, can I use this SSD1306 library with FreeRTOS, I think it will be very interesting, we could use an SD card with bitmaps in it and print them on the screen with the OLED display.
Thanks, Sir!
if u have possible provide with spi interfacing
I am having a problem in ssd1306.c with undefined references to ‘hi2c1’. What fixes can I do?
you need to enable the I2C in cubeMX. That’s how the OLED will connect to the MCU
i have enabled i2c in cubeMX,why i have the same problem? maybe because there exist 2 i2c?
the code is set to use the i2c1. Either enable that or change the code to use the I2C2
That’s a really helpful tutorial. I want to know if I can connect MPU6050 and the LCD to the same pins at the same time (using I2C only). Will the config of any affect the other.
Of course you can. That’s the entire purpose of I2C. With 7 bit addressing, you can connect upto 128 devices with just 2 pins.
I have a video on it too… Connecting on the same pins https://youtu.be/xxphp9wDnHA
Thanks a lot!! I really Appreciate it!
Hi, I really liked the tutorial, I wandering if this code can be used for a NUCLEO-F446RE (STM32F446RE)? I have been trying to make it work but I haven’t been able to. Thanks.
Yes , check this video https://www.youtube.com/watch?v=Z6VyFYzQWSs. Just need to change #include “stm32f1xx_hal.h” to f4 inside ssd1306.h.
what function has this code line?
It’s defined in main.c file
I don´t have money for you but, I would like to tell you “I LOVE YOU S MUC FOR THIS.”
Is it possible to interface the lcd 128x32u using your library?
why it is can not downloaded
try right click on the download and open in new tab
Thank you for your good writing and explanation.
Hello,
Thank you .
I downloaded the zip file and tried to build the project.
But I have below error :
./Inc/fonts.h:41:10: fatal error: stm32f1xx_hal.h: No such file or directory
What do you think? Can you share me this library please?
create your own project, and then use the library files from this one.
It works if you change to the same header file as the MCU you use.
Thanks for this tutorial! Excellent job! I ran into a problem compiling the code first time in a C++ project in STM32CubeIDE: “error: ‘C’ does not name a type; did you mean ‘_C’?” Needed to add quotation marks on C to get it to compile correctly: extern “C” {
Hi,
Where is the link for all these libraries which you are mentioned in the above tutorials?
click download and look in the src and inc folders
If you click on the download but the download does not start, you right click on the download button then copy the address of the line then paste in the search bar.
The link is obviously broken.. link to a github repo would be much better
Can Anyone send me the library for SSD1309 for STM32?
good work
good work
hi there, really good thanks.. may i ask, could this ssd1306 driver be repurposed for a ssd1327 (128×128) i2c oled ? im using the same ssd1306 code with a different init sequence, however the oled simply doesnt display anything.. any help would be appreciated.. kind thanks
Hi! Thanks, it worked perfectly. Is there any LCDAssistant avaliable for Linux distributions?
Good afternoon. Tell me how you can edit your code to use a smaller buffer?
Brother I started the Payment Process but it says you have exceeded the limit for receiving any more funds.
If this resolves just reply.
Thanks for this contribution
I don’t know what the issue is. It’s fine though. Keep visiting and that’s enough 🙂
Hello,
I need ssd1306 code for stm8s controller. Actually i have done this , but the problem i am facing is font or size. I am not able to change the size of the letter in my code.
The library i used is from this site.
Please help me out how can i change the size.
http://embedded-lab.com/blog/stm8-microcontrollers-final-chapters/3/
Please help me out how can i change the size.
Thanks you.
m.k.verma795@gmail.com
just google some font generator or look in the arduino librarries, you can find different fonts there
hello sir i want ask you something, i make this code to stm32 bluephill and then i get error selected processor does not support `dsb 0xF’ in Thumb mode
Hallo awesome library
only i have this following error message and i dont know how to get around it can you please help me with it?
.\Objects\OLED_i2c.axf: Error: L6218E: Undefined symbol Font_11x18 (referred from main.o).
.\Objects\OLED_i2c.axf: Error: L6218E: Undefined symbol SSD1306_GotoXY (referred from main.o).
.\Objects\OLED_i2c.axf: Error: L6218E: Undefined symbol SSD1306_Init (referred from main.o).
.\Objects\OLED_i2c.axf: Error: L6218E: Undefined symbol SSD1306_Puts (referred from main.o).
.\Objects\OLED_i2c.axf: Error: L6218E: Undefined symbol SSD1306_UpdateScreen (referred from main.o).
Not enough information to list image symbols.
Not enough information to list load addresses in the image map.
Finished: 2 information, 0 warning and 5 error messages.
“.\Objects\OLED_i2c.axf” – 5 Error(s), 0 Warning(s).
Edit:
Nevermind i fixed it already, i was using Keilv5 IDE, where you cannot just copy paste into the source and inc folder, but you have to add the item to the group by right clicking,
and then i modify it for my stm32f030xx and it worked fine, thank you again
thank you for your code just send you a coffee , you saved me some times
i want sent u donate but we are Boycott bye united state.
very very very thanks 🙂
the best likable aspiration for you.
Thanks Again
from IRAN
no worries.. keep supporting this website that’s enough
hi! excellent project, but I have a problem. when I download the .zip, i don´t see any libraries fonts.h, test.h, and ssd1306.h, and neither do libraries fonts.c, test.c and ssd1306.h; but I do see libraries font.d and font.o, likewise with test and ssd1306. Are these libraries similar to .c and .h?
HI
IT IS VERY HARD TO SWITCH ON STM32 FROM AVR 8 BIT BUT YOU DID A GREAT JOB FOR ALL PEOPLE LIKE ME . THANKS
Thank you for the example, got it working on Nucleo-L476RG board
Was anyone able to get this to work on a STM32F466RE?
If you mean 446RE, than yes I got it working.
I adapted the code for Nucleo-32, it works perfectly but sometimes it stops working for no reason.
Once the display just scrolled down alone and almost half-top was the bottom part of the display. Then I disassembled the display to try to reset it or something but when I assembled it again it stopped working. This happened to me before but without de scrolling.
The code works perfectly, I was just adjusting some parameters. I have searched some information about it and some people says it’s because of using the nucleo’s power supply but it doesn’t work when I put an external input voltage to the display. Other people says that it is because its power supply is 3V3 not 5V as in this guide but I have also tried it and guess what, sometimes it works and but when you disassemble the display it doesn’t.
If anyone knows why this happens please tell me.
MUCHAS GRACIAS. It works perfectly, you saved my day, I didn’t know how to use it in keil. Thank you so much.
STM32F103 (BLUE-PILL)
SCK (oled) to PB6
SDA(oled) to PB7
Works very well on my STM32F407 board, Thank you!
A detail…
The ssd1306_I2C_WriteMulti() function has a little bug in the counters, that is the reason why @Oleksandr Gusiev had to change SSD1306_WIDTH 128 to 129
Here is the fix
void ssd1306_I2C_WriteMulti(uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
uint8_t dt[256];
dt[0] = reg;
uint8_t i;
for(i = 0; i < count; i++)
dt[i+1] = data[i];
HAL_I2C_Master_Transmit(&hi2c1, address, dt, count+1, 10);
}
I hope it can help to another freaky electronic lover like us 😉
Thanks.. will check and update the code
/* USER CODE BEGIN Includes */
#include “ssd1306.h”
#include “i2c-lcd.h”
/* USER CODE END Includes */
Why i2c-lcd.h in code exists,but in video are not??
/* USER CODE BEGIN Includes */
#include “ssd1306.h”
#include “i2c-lcd.h”
/* USER CODE END Includes */
Why i2c-lcd.h in code exists,but in video are not?
How I can Put float number from adc in the display?
google it. It depends on what IDE you are using.
/* Private variables ———————————————————*/
//variable para LCD
char buf[25];
int dato=1;
…….
…….
while (1)
{
dato +=1;
if(dato>1000)
dato = 5;
dato = ((float)dato/24); // for example
sprintf(buf,”Dat:%.1f”,dato); //convert dato to string
SSD1306_GotoXY (0,0);
SSD1306_Puts (buf, &Font_11x18, 1);
SSD1306_UpdateScreen(); //Update the LCD
//End of LCD display
HAL_Delay(100);
SSD1306_Clear();
}
Thanks Working good,
please tell me command to clear lcd.
to clear lcd, you need to send 0x01
But I prefer sending blank (‘ ‘) as data
thanks….
it was fantastic
Hello. I followed your guide. Thanks a lot, it helped me clarify some points, but i have some troubles. First of all https://goo.gl/XD3yQC there are some dots at right side of screen (tested on two screens, same problem). And the second, but the most important, during run in debug, screen looks https://goo.gl/UMFquG at any
debug step, and it is always so when boot pins in such a state. Please, relpy, if possible. Thanks.
I fixed this issues. First problem with point to the right – bug into the lib. You should change #define SSD1306_WIDTH 128 in ssd1306.h to 129, cause numeration is starts from zero, not 1. The second problem was it that, I changed boot pins to 1. Both should be at 0.
In mi OLED work #define SSD1306_WIDTH 130
many thanks for this, really good c code
Hi, thanks for the explanation, I’m trying to port this code to a STM32L4 family.
I have managed to change all STM32f1xx lines. As well as changes the I2C number that I’m using hi2c3.
What’s is strange is that I’m getting only one error now which is on a completely different part of the code. It’s telling me the variable “count” needs a constant value. So maybe it’s not receiving anything.
void ssd1306_I2C_WriteMulti(uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
uint8_t dt[count + 1];
dt[0] = reg;
uint8_t i;
for(i = 1; i <= count; i++)
dt[i] = data[i-1];
HAL_I2C_Master_Transmit(&hi2c3, address, dt, count, 10);
}
thanks,very professional and useful.
Thank you very much! I’ve used this display in my project following your post and it works perfectly! Please, keep doing more stm32 tutorials, very interesting and useful!
Hi there! If I connect directly sda and scl wires without external resistor, Is it ok?
Yes it is completely fine
No it’s not, take a look here:
https://learn.sparkfun.com/tutorials/i2c/i2c-at-the-hardware-level