Driver and example for SSD1306 128x64 I2C display (#254)
This commit is contained in:
		
							parent
							
								
									e71919410d
								
							
						
					
					
						commit
						5b12ba54dc
					
				
					 9 changed files with 644 additions and 0 deletions
				
			
		
							
								
								
									
										22
									
								
								extras/ssd1306/LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								extras/ssd1306/LICENSE
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2015 Frank Bargstedt | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
| 
 | ||||
							
								
								
									
										27
									
								
								extras/ssd1306/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								extras/ssd1306/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| # Driver for I2C SSD1306 128x64 OLED LCD | ||||
| 
 | ||||
| This driver is written for usage with the ESP8266 and FreeRTOS ([esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos)). | ||||
| 
 | ||||
| ### Usage | ||||
| 
 | ||||
| Before using the SSD1306 LCD module, the function `i2c_init(SCL_PIN, SDA_PIN)` needs to be called to setup the I2C interface and then you must call ssd1306_init(). | ||||
| 
 | ||||
| #### Example  | ||||
| 
 | ||||
| ``` | ||||
| #define SCL_PIN GPIO_ID_PIN(0) | ||||
| #define SDA_PIN GPIO_ID_PIN(2) | ||||
| ... | ||||
| 
 | ||||
| i2c_init(SCL_PIN, SDA_PIN); | ||||
| 
 | ||||
| if (ssd1306_init()) { | ||||
| // An error occured, while performing SSD1306 init init (E.g device not found etc.) | ||||
| } | ||||
| 
 | ||||
| // rest of the code | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										9
									
								
								extras/ssd1306/component.mk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								extras/ssd1306/component.mk
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| # Component makefile for extras/ssd1306
 | ||||
| 
 | ||||
| # expected anyone using ssd1306 driver includes it as 'ssd1306/ssd1306.h'
 | ||||
| INC_DIRS += $(ssd1306_ROOT).. | ||||
| 
 | ||||
| # args for passing into compile rule generation
 | ||||
| ssd1306_SRC_DIR =  $(ssd1306_ROOT) | ||||
| 
 | ||||
| $(eval $(call component_compile_rules,ssd1306)) | ||||
							
								
								
									
										376
									
								
								extras/ssd1306/ssd1306.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								extras/ssd1306/ssd1306.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,376 @@ | |||
| #include <stdio.h> | ||||
| #include <i2c/i2c.h> | ||||
| #include <FreeRTOS.h> | ||||
| #include <task.h> | ||||
| #include "ssd1306.h" | ||||
| 
 | ||||
| /* SSD1306 commands */ | ||||
| #define SSD1306_SET_MEM_ADDR_MODE   (0x20) | ||||
| #define SSD1306_ADDR_MODE_HORIZ     (0x0) | ||||
| #define SSD1306_ADDR_MODE_VERT      (0x1) | ||||
| #define SSD1306_ADDR_MODE_PAGE      (0x2) | ||||
| 
 | ||||
| #define SSD1306_SET_COL_ADDR        (0x21) | ||||
| #define SSD1306_SET_PAGE_ADDR       (0x22) | ||||
| #define SSD1306_SET_DISP_START_LINE (0x40) | ||||
| #define SSD1306_SET_CONTRAST        (0x81) | ||||
| #define SSD1306_SET_SEGMENT_REMAP0  (0xA0) | ||||
| #define SSD1306_SET_SEGMENT_REMAP1  (0xA1) | ||||
| #define SSD1306_SET_ENTIRE_DISP_ON  (0xA5) | ||||
| #define SSD1306_SET_ENTIRE_DISP_OFF (0xA4) | ||||
| #define SSD1306_SET_INVERSION_OFF   (0xA6) | ||||
| #define SSD1306_SET_INVERSION_ON    (0xA7) | ||||
| 
 | ||||
| #define SSD1306_SET_MUX_RATIO       (0xA8) | ||||
| #define SSD1306_MUX_RATIO_MASK      (0x3F) | ||||
| #define SSD1306_SET_DISPLAY_OFF     (0xAE) | ||||
| #define SSD1306_SET_DISPLAY_ON      (0xAF) | ||||
| #define SSD1306_SET_SCAN_DIR_FWD    (0xC0) | ||||
| #define SSD1306_SET_SCAN_DIR_BWD    (0xC8) | ||||
| #define SSD1306_SET_DISPLAY_OFFSET  (0xD3) | ||||
| #define SSD1306_SET_OSC_FREQ        (0xD5) | ||||
| #define SSD1306_SET_PRE_CHRG_PER    (0xD9) | ||||
| 
 | ||||
| #define SSD1306_SET_COM_PINS_HW_CFG (0xDA) | ||||
| #define SSD1306_COM_PINS_HW_CFG_MASK    (0x32) | ||||
| #define SSD1306_SEQ_COM_PINS_CFG    (0x02) | ||||
| #define SSD1306_ALT_COM_PINS_CFG    (0x12) | ||||
| #define SSD1306_COM_LR_REMAP_OFF    (0x02) | ||||
| #define SSD1306_COM_LR_REMAP_ON     (0x22) | ||||
| 
 | ||||
| #define SSD1306_SET_DESEL_LVL       (0xDB) | ||||
| #define SSD1306_SET_NOP             (0xE3) | ||||
| 
 | ||||
| #define SSD1306_SET_CHARGE_PUMP     (0x8D) | ||||
| #define SSD1306_CHARGE_PUMP_EN      (0x14) | ||||
| #define SSD1306_CHARGE_PUMP_DIS     (0x10) | ||||
| 
 | ||||
| #ifdef SSD1306_DEBUG | ||||
| #define debug(fmt, ...) printf("%s" fmt "\n", "SSD1306", ## __VA_ARGS__); | ||||
| #else | ||||
| #define debug(fmt, ...) | ||||
| #endif | ||||
| 
 | ||||
| /* Issue a command to SSD1306 device
 | ||||
|  * format such follows: | ||||
|  * |S|Slave Address|W|ACK|0x00|Command|Ack|P| | ||||
|  *  | ||||
|  * in case of two-bytes command here will be Data byte | ||||
|  * right after command byte. | ||||
|  */ | ||||
| int ssd1306_command(uint8_t cmd) | ||||
| { | ||||
|     i2c_start(); | ||||
|     if (!i2c_write(SSD1306_I2C_ADDR << 1)) { | ||||
|         debug("Error while xmitting I2C slave address\n"); | ||||
|         i2c_stop(); | ||||
|         return -EIO; | ||||
|     } | ||||
|     if (!i2c_write(0x00)) { | ||||
|         debug("Error while xmitting transmission type\n"); | ||||
|         i2c_stop(); | ||||
|         return -EIO; | ||||
|     } | ||||
| 
 | ||||
|     if (!i2c_write(cmd)) { | ||||
|         debug("Error while xmitting command: 0x%02X\n", cmd); | ||||
|         i2c_stop(); | ||||
|         return -EIO; | ||||
|     } | ||||
| 
 | ||||
|     i2c_stop(); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* Perform default init routine according
 | ||||
| * to SSD1306 datasheet from adafruit.com */ | ||||
| int ssd1306_init() | ||||
| { | ||||
|     if (!ssd1306_display_on(false)                                  && | ||||
|         !ssd1306_set_osc_freq(0x80)                                 && | ||||
|         !ssd1306_set_mux_ratio(SSD1306_ROWS-1)                      && | ||||
|         !ssd1306_set_display_offset(0x0)                            && | ||||
|         !ssd1306_set_display_start_line(0x0)                        && | ||||
|         !ssd1306_set_charge_pump_enabled(true)                      && | ||||
|         !ssd1306_set_mem_addr_mode(SSD1306_ADDR_MODE_HORIZ)         && | ||||
|         !ssd1306_set_segment_remapping_enabled(false)               && | ||||
|         !ssd1306_set_scan_direction_fwd(true)                       && | ||||
|         !ssd1306_set_com_pin_hw_config(SSD1306_ALT_COM_PINS_CFG)    && | ||||
|         !ssd1306_set_contrast(0x9f)                                 && | ||||
|         !ssd1306_set_precharge_period(0xf1)                         && | ||||
|         !ssd1306_set_deseltct_lvl(0x40)                             && | ||||
|         !ssd1306_set_whole_display_lighting(true)                   && | ||||
|         !ssd1306_set_inversion(false)                               && | ||||
|         !ssd1306_display_on(true)) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return -EIO; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     * frame buffer of SSD1306 consists of 8 pages of 128 bits each | ||||
|     * | ||||
| */ | ||||
| int ssd1306_load_frame_buffer(uint8_t buf[], uint16_t len) | ||||
| { | ||||
|     uint16_t i; | ||||
|     uint8_t j; | ||||
| 
 | ||||
|     ssd1306_set_column_addr(0, 127); | ||||
|     ssd1306_set_page_addr(0, 7); | ||||
| 
 | ||||
|     for (i=0; i<len; i++) { | ||||
|         i2c_start(); | ||||
|         if (!i2c_write(SSD1306_I2C_ADDR << 1)) { | ||||
|             debug("Error while xmitting I2C slave address\n"); | ||||
|             i2c_stop(); | ||||
|             return -EIO; | ||||
|         } | ||||
|         if (!i2c_write(0x40)) { | ||||
|             debug("Error while xmitting transmission type\n"); | ||||
|             i2c_stop(); | ||||
|             return -EIO; | ||||
|         } | ||||
| 
 | ||||
|         for (j=0;j<16;j++) { | ||||
|             if (!i2c_write(buf[i])) { | ||||
|                 debug("Error while writing to GDDRAM\n"); | ||||
|                 i2c_stop(); | ||||
|                 return -EIO; | ||||
|             } | ||||
|             i++; | ||||
|         } | ||||
|         i--; | ||||
|         i2c_stop(); | ||||
|         taskYIELD(); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int ssd1306_clear_screen() | ||||
| { | ||||
|     uint16_t i = 0; | ||||
|     uint8_t j = 0; | ||||
| 
 | ||||
|     ssd1306_set_column_addr(0, 127); | ||||
|     ssd1306_set_page_addr(0, 7); | ||||
| 
 | ||||
|     while (i < (SSD1306_ROWS*SSD1306_COLS/8)) { | ||||
|         i2c_start(); | ||||
|         if (!i2c_write(SSD1306_I2C_ADDR << 1)) { | ||||
|             debug("Error while xmitting I2C slave address\n"); | ||||
|             i2c_stop(); | ||||
|             return -EIO; | ||||
|         } | ||||
|         if (!i2c_write(0x40)) { | ||||
|             debug("Error while xmitting transmission type\n"); | ||||
|             i2c_stop(); | ||||
|             return -EIO; | ||||
|         } | ||||
| 
 | ||||
|         /* write 16 bytes of data and then give resources to another task */ | ||||
|         while (j < 16) { | ||||
|             if (!i2c_write(0x0)) { | ||||
|                 debug("Error while writing to GDDRAM\n"); | ||||
|                 i2c_stop(); | ||||
|                 return -EIO; | ||||
|             } | ||||
|             i++; | ||||
|             j++; | ||||
|         } | ||||
|         i--; | ||||
|         j = 0; | ||||
|         i2c_stop(); | ||||
|         taskYIELD(); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int ssd1306_display_on(bool on) | ||||
| { | ||||
|     if (on) | ||||
|         return ssd1306_command(SSD1306_SET_DISPLAY_ON); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_SET_DISPLAY_OFF); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_display_start_line(uint8_t start) | ||||
| { | ||||
|     return ssd1306_command(SSD1306_SET_DISP_START_LINE | start); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_display_offset(uint8_t offset) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_DISPLAY_OFFSET))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(offset); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_charge_pump_enabled(bool enabled) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_CHARGE_PUMP))) | ||||
|         return err; | ||||
| 
 | ||||
|     if (enabled) | ||||
|         return ssd1306_command(SSD1306_CHARGE_PUMP_EN); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_CHARGE_PUMP_DIS); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_mem_addr_mode(uint8_t mode) | ||||
| { | ||||
|     if (mode >= 0x3) | ||||
|         return -EINVAL; | ||||
| 
 | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_MEM_ADDR_MODE))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(mode); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_segment_remapping_enabled(bool on) | ||||
| { | ||||
|     if (on) | ||||
|         return ssd1306_command(SSD1306_SET_SEGMENT_REMAP1); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_SET_SEGMENT_REMAP0); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_scan_direction_fwd(bool fwd) | ||||
| { | ||||
|     if (fwd) | ||||
|         return ssd1306_command(SSD1306_SET_SCAN_DIR_FWD); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_SET_SCAN_DIR_BWD); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_com_pin_hw_config(uint8_t config) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_COM_PINS_HW_CFG))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(config & SSD1306_COM_PINS_HW_CFG_MASK); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_contrast(uint8_t contrast) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_CONTRAST))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(contrast); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_inversion(bool on) | ||||
| { | ||||
|     if (on) | ||||
|         return ssd1306_command(SSD1306_SET_INVERSION_ON); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_SET_INVERSION_OFF); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_osc_freq(uint8_t osc_freq) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_OSC_FREQ))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(osc_freq); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_mux_ratio(uint8_t ratio) | ||||
| { | ||||
|     if (ratio < 15) | ||||
|         return -EINVAL; | ||||
| 
 | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_MUX_RATIO))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(ratio); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_column_addr(uint8_t start, uint8_t stop) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_COL_ADDR))) | ||||
|         return err; | ||||
| 
 | ||||
|     if ((err = ssd1306_command(start))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(stop); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_page_addr(uint8_t start, uint8_t stop) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_PAGE_ADDR))) | ||||
|         return err; | ||||
| 
 | ||||
|     if ((err = ssd1306_command(start))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(stop); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_precharge_period(uint8_t prchrg) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_PRE_CHRG_PER))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(prchrg); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_deseltct_lvl(uint8_t lvl) | ||||
| { | ||||
|     int err = 0; | ||||
|     if ((err = ssd1306_command(SSD1306_SET_DESEL_LVL))) | ||||
|         return err; | ||||
| 
 | ||||
|     return ssd1306_command(lvl); | ||||
| } | ||||
| 
 | ||||
| int ssd1306_set_whole_display_lighting(bool light) | ||||
| { | ||||
|     if (light) | ||||
|         return ssd1306_command(SSD1306_SET_ENTIRE_DISP_ON); | ||||
| 
 | ||||
|     return ssd1306_command(SSD1306_SET_ENTIRE_DISP_OFF); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* one byte of xbm - 8 dots in line of picture source
 | ||||
|  * one byte of fb - 8 rows for 1 column of screen | ||||
|  */ | ||||
| int ssd1306_load_xbm(uint8_t *xbm, uint8_t *fb) | ||||
| { | ||||
|     uint8_t bit = 0; | ||||
| 
 | ||||
|     int row = 0; | ||||
|     int column = 0; | ||||
|     for (row = 0; row < SSD1306_ROWS; row ++) { | ||||
|         for (column = 0; column < SSD1306_COLS/8; column++) { | ||||
|             uint16_t xbm_offset = row * 16  + column; | ||||
|             for (bit = 0; bit < 8; bit++) { | ||||
|                 if (*(xbm + xbm_offset) & 1 << bit) { | ||||
|                     *(fb + SSD1306_COLS*(row/8)+column*8+bit) |= 1 << row%8; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ssd1306_load_frame_buffer(fb, SSD1306_ROWS*SSD1306_COLS/8); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										50
									
								
								extras/ssd1306/ssd1306.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								extras/ssd1306/ssd1306.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| #ifndef _SSD1306__H_ | ||||
| #define _SSD1306__H_ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| // shifted
 | ||||
| #define SSD1306_I2C_ADDR    (0x3C) | ||||
| 
 | ||||
| #define SSD1306_ROWS        (64) | ||||
| #define SSD1306_COLS        (128) | ||||
| 
 | ||||
| /* Issue single command on SSD1306 */ | ||||
| int ssd1306_command(uint8_t cmd); | ||||
| 
 | ||||
| /* Default init for SSD1306 */ | ||||
| int ssd1306_init(); | ||||
| 
 | ||||
| /* Load picture in xbm format into SSD1306 RAM
 | ||||
|  * xbm - pointer to xbm picture array | ||||
|  * fb - pointer fo local buffer for storing converted xbm image | ||||
|  */ | ||||
| int ssd1306_load_xbm(uint8_t *xbm, uint8_t *fb); | ||||
| 
 | ||||
| /* Load local framebuffer into SSD1306 RAM */ | ||||
| int ssd1306_load_frame_buffer(uint8_t buf[], uint16_t len); | ||||
| 
 | ||||
| /* Clears SSD1306 ram */ | ||||
| int ssd1306_clear_screen(); | ||||
| 
 | ||||
| int ssd1306_display_on(bool on); | ||||
| int ssd1306_set_display_start_line(uint8_t start); | ||||
| int ssd1306_set_display_offset(uint8_t offset); | ||||
| int ssd1306_set_charge_pump_enabled(bool enabled); | ||||
| int ssd1306_set_mem_addr_mode(uint8_t mode); | ||||
| int ssd1306_set_segment_remapping_enabled(bool on); | ||||
| int ssd1306_set_scan_direction_fwd(bool fwd); | ||||
| int ssd1306_set_com_pin_hw_config(uint8_t config); | ||||
| int ssd1306_set_contrast(uint8_t contrast); | ||||
| int ssd1306_set_inversion(bool on); | ||||
| int ssd1306_set_osc_freq(uint8_t osc_freq); | ||||
| int ssd1306_set_mux_ratio(uint8_t ratio); | ||||
| int ssd1306_set_column_addr(uint8_t start, uint8_t stop); | ||||
| int ssd1306_set_page_addr(uint8_t start, uint8_t stop); | ||||
| int ssd1306_set_precharge_period(uint8_t prchrg); | ||||
| int ssd1306_set_deseltct_lvl(uint8_t lvl); | ||||
| int ssd1306_set_whole_display_lighting(bool light); | ||||
| 
 | ||||
| #endif // _SSD1306__H_
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue