SSD1306 I2C Display Driver  1.2.1
This library is developed to control SSD1306 I2C OLED Display
ssd1306_i2c_embedded.c
1 /*
2  Copyright (C) 2016-2017 Alexey Dynda
3 
4  This file is part of SSD1306 library.
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 
21 #include "ssd1306_i2c.h"
22 
23 #include "intf/ssd1306_interface.h"
24 #include "ssd1306_i2c_conf.h"
25 
26 
32 #if defined(SSD1306_EMBEDDED_I2C)
33 
34 static uint8_t s_sda = SSD1306_SDA;
35 static uint8_t s_scl = SSD1306_SCL;
36 
37 #include <avr/interrupt.h>
38 
39  #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
40  // at 8Mhz each command takes ~ 0.125us
41  #define DDR_REG DDRB
42  #define PORT_REG PORTB
43  #else // For Atmega
44  // at 16Mhz each command takes ~ 0.0625us
45  #define DDR_REG DDRC
46  #define PORT_REG PORTC
47  #endif
48 
49 
50 #ifndef F_CPU
51  #warning "F_CPU is not defined, there can be I2C issues"
52  #define F_CPU 8000000
53 #endif
54 #define CPU_CYCLE_NS (1000000000/F_CPU)
55 
56 // each delay loop takes 4 cycles: nop(1), dec(1), jnz(2)
57 #define DELAY_LOOP_CYCLES 4
58 #define ssd1306_delay(x) for(uint8_t i2=x; i2>0; i2--){__asm__("nop\n\t");}
59 
63 #define SSD1306_I2C_START_STOP_DELAY 600
64 #define SSD1306_I2C_RISE_TIME 300
65 #define SSD1306_I2C_FALL_TIME 300
66 #define SSD1306_I2C_DATA_HOLD_TIME 300
67 #define SSD1306_I2C_IDLE_TIME 1300
68 #define SSD1306_I2C_CLOCK 2500
69 
70 
71 #define I2C_START_STOP_DELAY ((SSD1306_I2C_START_STOP_DELAY/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
72 
73 #define I2C_RISE_TIME ((SSD1306_I2C_RISE_TIME/CPU_CYCLE_NS)/DELAY_LOOP_CYCLES)
74 
75 #define I2C_DATA_HOLD_TIME ((SSD1306_I2C_DATA_HOLD_TIME/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
76 
77 #define I2C_IDLE_TIME (((SSD1306_I2C_IDLE_TIME/CPU_CYCLE_NS) + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
78 
79 #define I2C_HALF_CLOCK (((SSD1306_I2C_CLOCK - SSD1306_I2C_FALL_TIME - SSD1306_I2C_RISE_TIME - SSD1306_I2C_FALL_TIME)/CPU_CYCLE_NS/2 \
80  )/DELAY_LOOP_CYCLES)
81 
82 
83 /* I2C HIGH = PORT as INPUT(0) and PULL-UP ENABLE (1) */
84 #define DIGITAL_WRITE_HIGH(DREG, PREG, BIT) { DREG &= ~(1 << BIT); PREG |= (1 << BIT); }
85 
86 /* I2C LOW = PORT as OUTPUT(1) and OUTPUT LOW (0) */
87 #define DIGITAL_WRITE_LOW(DREG, PREG, BIT) { DREG |= (1 << BIT); PREG &= ~(1 << BIT); }
88 
89 static uint8_t oldSREG;
90 static bool interruptsOff = false;
91 
95 void ssd1306_i2cStart(void)
96 {
97  oldSREG = SREG;
98  cli();
99  interruptsOff = true;
100  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
101  ssd1306_delay(I2C_START_STOP_DELAY);
102  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl); // Set to LOW
103  ssd1306_delay(I2C_HALF_CLOCK);
104  ssd1306_i2cSendByte((SSD1306_SA << 1) | 0);
105 }
106 
107 void ssd1306_i2cStop(void)
108 {
109  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
110  ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
111  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl); // Set to HIGH
112  ssd1306_delay(I2C_START_STOP_DELAY);
113  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda); // Set to HIGH
114  ssd1306_delay(I2C_IDLE_TIME);
115  if (interruptsOff)
116  {
117  SREG = oldSREG;
118  interruptsOff = false;
119  }
120 }
121 
126 void ssd1306_i2cSendByte(uint8_t data)
127 {
128  uint8_t i;
129  for(i=0; i<8; i++)
130  {
131  if((data << i) & 0x80)
132  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda)
133  else
134  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda);
135  ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
136 
137  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
138  ssd1306_delay(I2C_HALF_CLOCK);
139 
140  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
141  ssd1306_delay(I2C_HALF_CLOCK);
142  }
143  // generating confirmation impulse
144  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda);
145  ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
146  DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
147  ssd1306_delay(I2C_HALF_CLOCK);
148  DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
149  ssd1306_delay(I2C_HALF_CLOCK);
150 }
151 
152 #endif
153 
154 
void ssd1306_i2cStop()
void ssd1306_i2cStart()
void ssd1306_i2cSendByte(uint8_t data)