1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#include <util/twi.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include "i2c.h"
#include "ssd1306_display_driver.h"
#define SSD1306_ADDR 0x3c
#define SSD1306_CMD_REG 0x00
#define SSD1306_DATA_REG 0x40
//on the datasheet we have 32 extra rows (4 more pages) of GDRAM that don't fit on the display; we just ignore them everywhere
#define SCREEN_PAGE_CNT SCREEN_RES_Y / 8
#define I2C_WRITE 0
#define I2C_READ 1
void screen_init() {
#ifdef DEBUG_BUILD
printf("initlizing SSD1306 display driver\n");
#endif
//turn on screen while we configure shit, it might look cooler
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xaf);
//don't inverse display
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xa6);
//set contrast to 255 (try chainging?)
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x81, 0xff});
//set lower nibble of column ptr to 0
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
//set upper nibble of column ptr to 0
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
//memory mode is paging
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x20, 0x02});
//no vertical shift
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xd3, 0x00});
//page address is at 0
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0);
//ram display start register is at 0
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x40);
//column address 0 is mapped to seg0
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xa0); //a1
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xc8);
//set mux ratio to 32 mux
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xa8, 0x1f});
//alternative COM hardware mapping (stolen from lib)
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xda, 0x02});
//volage regulator on
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x8d, 0x14});
//set clock divider to zero, and oscillator frequency as high as it goes
//Maybe we save battery to run slower?
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xd5, 0xf0}); //TODO look
//deactivate scroll
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x2e);
}
void screen_off() { i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xaf); }
void screen_on() { i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xae); }
void screen_update() {
for(int on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_DATA_REG, sizeof(screen_buffer), screen_buffer);
}
}
#ifdef DEBUG_BUILD
//ugly code below
void scroll_test() {
//sets scroll area to whole screen
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 3, (uint8_t[]){0xa3, 0x00, 0x20});
//set up scroll options
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x29, 0x00, 0x00, 0x00, 0x04, 0x00});
//actually activate scroll
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x2f});
}
void screen_testdraw() {
unsigned int on_pix;
unsigned int on_page;
printf("running screen time tests\n");
printf("generating test image...\n");
for(on_pix = 0; on_pix < sizeof(screen_buffer); on_pix++)
screen_buffer[on_pix] = ((uint8_t)0xaa << (on_pix % 8));
printf("page mode, individual byte per i2c call...\n");
for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
for(on_pix = 0; on_pix < SCREEN_RES_X; on_pix++)
i2c_write_reg(SSD1306_ADDR, SSD1306_DATA_REG, screen_buffer[(on_page * 8) + on_pix]);
}
printf("page mode, 1 page per i2c call...\n");
for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_DATA_REG, SCREEN_RES_X, &screen_buffer[on_page * SCREEN_RES_X]);
}
}
#endif
|