Skip to content

Commit 861c880

Browse files
committed
add support for SH1106/SSD1306
1 parent 841f17c commit 861c880

File tree

8 files changed

+323
-22
lines changed

8 files changed

+323
-22
lines changed

img/res-mod-sh1106.jpg

130 KB
Loading

img/sch-sh1106.png

9.23 KB
Loading

img/sch.png

-99 Bytes
Loading

img/t-rex-demo-sh1106.gif

1.75 MB
Loading

readme.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Just 3 components needed:
1212

1313
[Youtube video](https://www.youtube.com/watch?v=635SnybBRD8)
1414

15+
**Update**
16+
Now supporting [OLED display SH1106/SSD1306 I2C](#using-oled-display-sh1106/ssd1306-i2c).
17+
1518
## Instructions
1619

1720
0. Assemble
@@ -22,6 +25,32 @@ Just 3 components needed:
2225
2. Play!
2326
3. Repeat from step 2
2427

28+
## Using OLED display SH1106/SSD1306 I2C
29+
30+
<img width="250" src="img/t-rex-demo-sh1106.gif" />
31+
32+
0. In order to use SH1106/SSD1306 you will need to add two 470 ohm resistors to the dispaly board.
33+
You can add these resistors right on top of 10k resistors that already present (or replace them).
34+
35+
<img width="250" src="img/res-mod-sh1106.jpg" />
36+
37+
1. Assemble
38+
39+
<img width="600" src="img/sch-sh1106.png" />
40+
41+
3. Select OLED display type at the beginning of `t-rex-duino.ino` sketch by uncommenting one of the following lines (SSD1309 selected by default).
42+
```
43+
//#define LCD_SSD1309
44+
//#define LCD_SH1106
45+
//#define LCD_SSD1306
46+
```
47+
Flash the sketch.
48+
49+
Note that in order to achieve desirable performance I2C is substantially overclocked (it works at 800kHz vs 400kHz as per display specification).
50+
It is possible that not every display will work under these conditions.
51+
The display I have works fine mostly, but a stray broken frame still appears now and then.
52+
As much as I can assume **small artifacts are unavoidable with this display**.
53+
2554
## License
2655

2756
MIT License © github.com/AlexIII

t-rex-duino/I2C.h

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Project name: T-rex-duino
3+
* Description: T-rex game from Chrome brower rewritten for Arduino
4+
* Project page: https://github.com/AlexIII/t-rex-duino
5+
* Author: github.com/AlexIII
6+
7+
* License: MIT
8+
*/
9+
10+
#ifndef _I2C_CALSS_H_
11+
#define _I2C_CALSS_H_
12+
13+
#include <compat/twi.h>
14+
15+
struct I2C {
16+
I2C() {}
17+
18+
static void init(const uint32_t clock) {
19+
TWSR = 0; // no prescaler
20+
TWBR = ((F_CPU/clock)-16)/2; // must be > 10 for stable operation
21+
}
22+
23+
static void deinit(void) {
24+
TWBR = 0;
25+
TWCR = 0;
26+
}
27+
28+
static uint8_t start(uint8_t address) {
29+
uint8_t twst, i;
30+
// send START condition
31+
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
32+
33+
// wait until transmission completed
34+
//while(!(TWCR & (1<<TWINT)));
35+
for(i = 255; i; --i) {
36+
if(TWCR & (1<<TWINT)) break;
37+
asm volatile("nop");
38+
asm volatile("nop");
39+
}
40+
if(!i) return 0xFF;
41+
42+
// check value of TWI Status Register. Mask prescaler bits.
43+
twst = TW_STATUS & 0xF8;
44+
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
45+
46+
// send device address
47+
TWDR = address;
48+
TWCR = (1<<TWINT) | (1<<TWEN);
49+
50+
// wail until transmission completed and ACK/NACK has been received
51+
//while(!(TWCR & (1<<TWINT)));
52+
for(i = 255; i; --i) {
53+
if(TWCR & (1<<TWINT)) break;
54+
asm volatile("nop");
55+
asm volatile("nop");
56+
}
57+
if(!i) return 0xFF;
58+
59+
// check value of TWI Status Register. Mask prescaler bits.
60+
twst = TW_STATUS & 0xF8;
61+
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
62+
63+
return 0;
64+
}
65+
66+
static void stop(void) {
67+
//send stop condition
68+
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
69+
70+
// wait until stop condition is executed and bus released
71+
//while(TWCR & (1<<TWSTO));
72+
for(uint8_t i = 255; i; --i) {
73+
if(!(TWCR & (1<<TWSTO))) break;
74+
asm volatile("nop");
75+
asm volatile("nop");
76+
}
77+
}
78+
79+
static uint8_t write(uint8_t data) {
80+
uint8_t twst;
81+
82+
// send data to the previously addressed device
83+
TWDR = data;
84+
TWCR = (1<<TWINT) | (1<<TWEN);
85+
86+
// wait until transmission completed
87+
//while(!(TWCR & (1<<TWINT)));
88+
uint8_t i;
89+
for(i = 255; i; --i) {
90+
if(TWCR & (1<<TWINT)) break;
91+
asm volatile("nop");
92+
asm volatile("nop");
93+
}
94+
if(!i) return 0xFF;
95+
96+
// check value of TWI Status Register. Mask prescaler bits
97+
twst = TW_STATUS & 0xF8;
98+
if( twst != TW_MT_DATA_ACK) return twst;
99+
return 0;
100+
}
101+
102+
static uint8_t readAck(void) {
103+
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
104+
//while(!(TWCR & (1<<TWINT)));
105+
for(uint8_t i = 255; i; --i) {
106+
if(TWCR & (1<<TWINT)) break;
107+
asm volatile("nop");
108+
asm volatile("nop");
109+
}
110+
return TWDR;
111+
}
112+
113+
static uint8_t readNak(void) {
114+
TWCR = (1<<TWINT) | (1<<TWEN);
115+
//while(!(TWCR & (1<<TWINT)));
116+
for(uint8_t i = 255; i; --i) {
117+
if(TWCR & (1<<TWINT)) break;
118+
asm volatile("nop");
119+
asm volatile("nop");
120+
}
121+
return TWDR;
122+
}
123+
};
124+
125+
126+
#endif

t-rex-duino/SH1106.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Project name: T-rex-duino
3+
* Description: T-rex game from Chrome brower rewritten for Arduino
4+
* Project page: https://github.com/AlexIII/t-rex-duino
5+
* Author: github.com/AlexIII
6+
7+
* License: MIT
8+
*/
9+
10+
#ifndef _SH1106_H_
11+
#define _SH1106_H_
12+
13+
#define SH1106_I2C_SCL_CLOCK 800000UL
14+
#define SH1106_I2C_ADDR 0b01111000
15+
#define SH1106_COMMAND 0x00
16+
#define SH1106_DATA 0x40
17+
18+
#define SH1106_COLS_USED 128
19+
#define SH1106_PAGES 8
20+
21+
#ifndef LCD_SSD1306
22+
#define SH1106_COLS_TOTAL 130
23+
#else
24+
#define SH1106_COLS_TOTAL SH1106_COLS_USED
25+
#endif
26+
27+
template<class I2C_TYPE>
28+
class SH1106 {
29+
I2C_TYPE &i2c;
30+
const uint16_t screenBufferSize;
31+
public:
32+
enum AddressingMode {
33+
HorizontalAddressingMode = 0x00,
34+
VerticalAddressingMode = 0x01,
35+
PageAddressingMode = 0x02,
36+
};
37+
SH1106(I2C_TYPE &i2c, const uint16_t screenBufferSize):
38+
i2c(i2c), screenBufferSize(screenBufferSize) {}
39+
void begin() {
40+
uint8_t col = 0;
41+
uint8_t page = 0;
42+
}
43+
void fillScreen(const uint8_t* buffer) {
44+
reinit();
45+
sendd(buffer, screenBufferSize);
46+
}
47+
void fillScreen(const uint8_t* buffer, const uint16_t size, const uint8_t stride = 0) { //stride is not supported
48+
reinit();
49+
sendd(buffer, size);
50+
}
51+
void setInverse(const bool v) {
52+
inverted = v;
53+
reinit();
54+
}
55+
//Only PageAddressingMode works for SH1106
56+
//Here we're emulating HorizontalAddressingMode programmatically
57+
void setAddressingMode(const AddressingMode addressingMode) {}
58+
59+
private:
60+
/* lcd control */
61+
void reinit() {
62+
i2c.deinit();
63+
i2c.init(SH1106_I2C_SCL_CLOCK);
64+
sendc(0xAF); //display on
65+
sendc(inverted? 0xA7 : 0xA6); //inversion
66+
}
67+
68+
/* send bytes */
69+
void sendc(const uint8_t cmd) {
70+
i2c.start(SH1106_I2C_ADDR);
71+
i2c.write(SH1106_COMMAND);
72+
i2c.write(cmd);
73+
i2c.stop();
74+
}
75+
void sendc(const uint8_t cmd1, const uint8_t cmd2) {
76+
i2c.start(SH1106_I2C_ADDR);
77+
i2c.write(SH1106_COMMAND);
78+
i2c.write(cmd1);
79+
i2c.write(cmd2);
80+
i2c.stop();
81+
}
82+
void sendc(const uint8_t cmd1, const uint8_t cmd2, const uint8_t cmd3) {
83+
i2c.start(SH1106_I2C_ADDR);
84+
i2c.write(SH1106_COMMAND);
85+
i2c.write(cmd1);
86+
i2c.write(cmd2);
87+
i2c.write(cmd3);
88+
i2c.stop();
89+
}
90+
void sendd(const uint8_t* d, uint16_t sz) {
91+
const uint8_t blackPx = inverted? 0xFF : 0;
92+
while(sz) { //page cycle
93+
sendc(0xB0 + page); //set page address to i (0..7)
94+
sendc(0x00 + (col&0x0F)); //Sets 4 lower bits of column address
95+
sendc(0x10 + (col>>4)); //Sets 4 higher bits of column address
96+
97+
i2c.start(SH1106_I2C_ADDR);
98+
i2c.write(SH1106_DATA);
99+
while(sz) { //column cycle
100+
i2c.write(*d++);
101+
--sz;
102+
if(++col >= SH1106_COLS_USED) {
103+
while(col++ < SH1106_COLS_TOTAL) i2c.write(blackPx);
104+
col = 0;
105+
break;
106+
}
107+
}
108+
i2c.stop();
109+
110+
if(col == 0 && ++page >= SH1106_PAGES) page = 0;
111+
}
112+
}
113+
114+
uint8_t col = 0;
115+
uint8_t page = 0;
116+
bool inverted = false;
117+
};
118+
119+
120+
#endif

0 commit comments

Comments
 (0)