-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi2c_oled_128x64.c
443 lines (358 loc) · 12.4 KB
/
i2c_oled_128x64.c
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
#include <string.h>
#include <signal.h>
#include <sys/msg.h>
#include "i2c_oled_128x64.h"
#include "msg_common.h"
#include "ascii2.h"
int g_fdOled;
char *g_pstroledDev="/dev/i2c-0";
uint8_t g_u8oledAddr=0x78>>1;
struct i2c_rdwr_ioctl_data g_i2c_iodata;
//---- i2c dev lock ----
struct flock g_i2cFdReadLock;
struct flock g_i2cFdWriteLock;
//---- 16x8_size ASCII char. frame buffer for oled display -----
struct oled_Ascii16x8_Frame_Buff {
bool refresh_on[4][16]; // 1-refresh 0-no refresh
char char_buff[4][16];//4 lines x 16 ASCII chars
} g_Oled_Ascii16x8_Frame={0};
/*-----------------------------------------
initiate i2c ioctl data
-----------------------------------------*/
void init_I2C_IOdata(void)
{
g_i2c_iodata.nmsgs=1;
g_i2c_iodata.msgs=(struct i2c_msg*)malloc(g_i2c_iodata.nmsgs*sizeof(struct i2c_msg));
g_i2c_iodata.msgs[0].len=2;
g_i2c_iodata.msgs[0].addr=g_u8oledAddr;
g_i2c_iodata.msgs[0].flags=0; //write
g_i2c_iodata.msgs[0].buf=(unsigned char*)malloc(2);
}
/*-----------------------------------------
free i2c ioctl data mem.
-----------------------------------------*/
void free_I2C_IOdata(void)
{
if(g_i2c_iodata.msgs != NULL)
free(g_i2c_iodata.msgs);
if(g_i2c_iodata.msgs[0].buf != NULL)
free(g_i2c_iodata.msgs[0].buf);
}
/*--------------send data or command to oled---------------
send DATA or COMMAND to oled, depending on oled_sig value
---------------------------------------------------------*/
void sendDatCmdoled(enum oled_sig datcmd,uint8_t val) {
int ret;
uint8_t sig;
if(datcmd == oled_SIG_CMD)
sig=0x00; //----send command
else
sig=0x40; //--send data
g_i2c_iodata.msgs[0].buf[0]=sig; // 0x00 for Command, 0x40 for data
g_i2c_iodata.msgs[0].buf[1]=val;
ret=ioctl(g_fdOled,I2C_RDWR,(unsigned long)&g_i2c_iodata);
if(ret<0)
{
printf("i2c ioctl read error!\n");
}
}
/*------ send command to oled ---------*/
void sendCmdOled(uint8_t cmd)
{
sendDatCmdoled(oled_SIG_CMD,cmd);
}
/*------ send data to oled ---------*/
void sendDatOled(uint8_t dat)
{
sendDatCmdoled(oled_SIG_DAT,dat);
}
/*----- open i2c slave and init ioctl -----*/
void init_I2C_Slave(void)
{
if((g_fdOled=open(g_pstroledDev,O_RDWR))<0)
{
perror("fail to open i2c bus");
exit(1);
}
else
printf("Open i2c bus successfully!\n");
//----- set g_fdOled
ioctl(g_fdOled,I2C_TIMEOUT,2);
ioctl(g_fdOled,I2C_RETRIES,1);
//------ try to lock file
intFcntlOp(g_fdOled,F_SETLK, F_WRLCK, 0, SEEK_SET,0);//write lock
printf("I2C fd lock operation finished.\n");
init_I2C_IOdata();
}
/*---------------------------------------------------------------
init OLED with default parameters
---------------------------------------------------------------*/
void initOledDefault(void)
{
sendCmdOled(0xAE); //display off
sendCmdOled(0x20); //set memory addressing mode
sendCmdOled(0x22); //[1:0]=00b-horizontal 01b-veritacal 10b-page addressing mode(RESET)
sendCmdOled(0xb0); // 0xb0~b7 set page start address for page addressing mode
sendCmdOled(0xc8);// set COM Output scan direction 0xc0-- COM0 to COM[N-1], 0xc8-- COM[N-1] to COM0
sendCmdOled(0x0f);//2); //0x00~0F, set lower column start address for page addressing mode
sendCmdOled(0x10); // 0x10~1F, set higher column start address for page addressing mode
sendCmdOled(0x40); //40~7F set display start line 0x01(5:0)
sendCmdOled(0x81); // contrast control
sendCmdOled(0x7f); //contrast value RESET=7Fh
sendCmdOled(0xa1); //set segment remap a0h--column 0 is mapped to SEG0, a1h--column 127 is mapped to SEG0
sendCmdOled(0xa6); //normal / reverse a6h--noraml, 1 in RAM displays; a7h--inverse, 0 in RAM displays.
sendCmdOled(0xa8); //multiplex ratio
sendCmdOled(0x3F); // 16MUX to 64MUX RESET=111111b, 0x1F for 128x32; 0x3F for 128x64
sendCmdOled(0xa4);// A4h-- resume to RAM content display(RESET), A5h--entire display ON.
sendCmdOled(0xd3);// set display offset, set vertical shift by COM from 0d~63d
sendCmdOled(0x00);
sendCmdOled(0xd5); // set desplay clock divide,
sendCmdOled(0xf0);// [7:4] osc. freq; [3:0] divide ratio, RESET is 00001000B
sendCmdOled(0xd9);// set pre-charge period
sendCmdOled(0x22);//[3:0] phase 1 period of up to 15 DCLK [7:4] phase 2 period of up to 15 DCLK
sendCmdOled(0xda);//--set COM pins hardware configuration
sendCmdOled(0x12);//[5:4] 0x02 for 128x32 0x12 for 128x64
sendCmdOled(0xdb);//set Vcomh deselect level
sendCmdOled(0x20);
sendCmdOled(0x8d);// charge pump setting
sendCmdOled(0x14);// [2]=0 disable charge pump, [2]=1 enbale charge pump
sendCmdOled(0xaf);// AE, display off(sleep mode), AF, display on in normal mode.
}
void fillOledDat(uint8_t dat)
{
uint8_t i,j;
//--sed page addressing mode---
sendCmdOled(0x20); //set memory addressing mode
sendCmdOled(0x22); //[1:0]=00b-horizontal 01b-veritacal 10b-page addressing mode(RESET)
for(i=0;i<8;i++)
{
sendCmdOled(0xb0+i); //0xB0~B7, page0-7
sendCmdOled(0x00); //00~0f,low column start address ?? no use !!
sendCmdOled(0x10); //10~1f, ???high column start address
for(j=0;j<128;j++) // write to 128 segs, 1 byte each seg.
{
sendDatOled(dat);
}
}
}
//----XXXXX to use clearOledV() instead !!!!
void clearOled(void)
{
int i,j;
//--sed page addressing mode---
sendCmdOled(0x20); //set memory addressing mode
sendCmdOled(0x22); //[1:0]=00b-horizontal 01b-veritacal 10b-page addressing mode(RESET)
for(i=0;i<8;i++)
{
sendCmdOled(0xb0+i); // 0xb0~b7 set page start address for page addressing mode
sendCmdOled(0x00); // low column start address
sendCmdOled(0x10); //0x10~1f high column start address,use 0x10 if no limits.
for(j=0;j<128;j++)
sendDatOled(0x00); //--clear GRAM
}
}
/*----------------------------------------------------
draw Ascii symbol on Oled
start_column: 0~7 (128x64)
start_row: 0~15;!!!!!!
------------------------------------------------------*/
void drawOledAscii16x8(uint8_t start_row, uint8_t start_column,unsigned char c)
{
int j;
//----replace non-ASCII symbol char with 127 'delta'
if(c<32 || c>127) c=127;
//----set mode---
//-----set as vertical addressing mode -----
sendCmdOled(0x20); //set memory addressing mode
sendCmdOled(0x01); //[1:0]=00b-horizontal 01b-veritacal 10b-page addressing mode(RESET)
//---set column addr. for horizontal mode
sendCmdOled(0x21);
sendCmdOled(start_column);//column start
sendCmdOled(start_column+7);//column end, !!!! 8x16 for one line only!!!
//---set page addr.
sendCmdOled(0x22);
sendCmdOled(start_row);// 0-7 start page
sendCmdOled(start_row+1);// 2 rows. 2x8=16 !!!! for one line only!!!!
for(j=0;j<16;j++)
sendDatOled(ascii_8x16[(c-0x20)*16+j]);
}
/*------------------------------------------------------------
Display ASCII chars in g_Oled_Ascii16x8_Frame.char_buff[]
onto the OLED.
ref_all=false: only applicable for those with .refresh_on[]=true
ref_all=true: refresh all chars in buff
------------------------------------------------------------*/
void refresh_Oled_Ascii32x18_Buff(bool ref_all)
{
int i,j;
if(ref_all){
memset(g_Oled_Ascii16x8_Frame.refresh_on[0],true,16*4); // refresh_on for all chars.
}
for(i=0;i<4;i++){//row
for(j=0;j<16;j++){//column
// printf("line=%d, buff[%d][%d]=%d ",2*i,i,j,g_Oled_Ascii16x8_Frame.refresh_on[i][j] );//only if refresh_on
if(g_Oled_Ascii16x8_Frame.refresh_on[i][j])//only if refresh_on
drawOledAscii16x8(2*i,8*j,g_Oled_Ascii16x8_Frame.char_buff[i][j]);
}
// printf("\n");
}
memset(g_Oled_Ascii16x8_Frame.refresh_on[0],false,16*4); // clear .refresh_on token then
}
/*-------------------------------------------------------------------
Push a string of chars(pstr) into g_Oled_Ascii16x8_Frame[]
within specified row number(nrow: 0~3),starting from (nstart*18) column.
nrow [0~3]
nstart [0~15]
----------------------------------------------------------------------*/
void push_Oled_Ascii32x18_Buff(const char* pstr, uint8_t nrow, uint8_t nstart)
{
int k;
int len=strlen(pstr);
if(len>16) len=16;
if(nrow>3){
printf("push_Oled_Ascii32x18_Buff(): row number is out of range [0~3]!\n");
return;
}
if(nstart>15){
printf("push_Oled_Ascii32x18_Buff(): start number is out of range [0~15]!\n");
return;
}
//-----set .refresh_on[] token
for(k=nstart; k<nstart+len; k++){
if( g_Oled_Ascii16x8_Frame.char_buff[nrow][k] != *(pstr+k-nstart) )//--check if its content changed
g_Oled_Ascii16x8_Frame.refresh_on[nrow][k]=true;
}
//-----copy string to buff row----
strncpy(g_Oled_Ascii16x8_Frame.char_buff[nrow]+nstart,pstr,len);
}
/*-------------------------------------------------------------
Draw a string of 16x8 ASCII chars onto the OLED
--------------------------------------------------------------*/
void drawOledStr16x8(uint8_t start_row, uint8_t start_column,const char* pstr)
{
int k;
int len=strlen(pstr);
if(len>16)len=16;
for(k=0;k<len;k++)
drawOledAscii16x8(start_row,start_column+8*k,*(pstr+k));
}
//--------- horizontal mode ----- FAIL !!!!
void drawOledAsciiHRC(uint8_t start_row, uint8_t start_column,unsigned char c)
{
int j;
sendCmdOled(0xb0+start_row); //0xB0~B7, page0-7
sendCmdOled(0x00+start_column); //00~0f,low column start address ?? no use !!
sendCmdOled(0x1f); //10~1f, ???high column start address
for(j=0;j<16;j++) // write to 128 segs, 1 byte each seg.
{
sendDatOled(ascii_8x16[(c-0x20)*16+j]);
}
}
//------file lock/unlock operation ----
int intFcntlOp(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
int ret,fcret;
struct flock lock;
if((fcret=fcntl(g_fdOled,F_GETFL,0))<0)
{
perror("fcntl to get lock");
exit(1);
}
switch(fcret & O_ACCMODE)
{
case O_RDONLY:
printf("Read only..\n");break;
case O_WRONLY:
printf("Write only..\n");break;
case O_RDWR:
printf("Read and Write ..\n");break;
default:
printf("File is not valid..\n");
}
//----init lock with value, otherwise "Invalid argument" error
lock.l_type=F_WRLCK; //--check whether F_WRLCK is lockable
lock.l_start=0;
lock.l_whence=SEEK_SET;
lock.l_len=0;
//---- check lock ---
if(fcntl(g_fdOled,F_GETLK,&lock)<0) //--lock return as UNLCK if is applicable, or it returns file's current lock.
{
perror("fcntl to get lock");
exit(1);
}
//-------------UNAPPLICABLE !!!!!
printf("lock.l_type: 0x%x\n",lock.l_type);
printf("F_WRLCK: 0x%x\n",F_WRLCK);
if((lock.l_type==F_WRLCK) || (lock.l_type==F_RDLCK) )
{
printf("File is locked by other process!\n");
exit(1);
}
//-----reset value
lock.l_type=type;
lock.l_start=offset;
lock.l_whence=whence;
lock.l_len=len;
//-----fcntl lock
if((ret=fcntl(fd,cmd,&lock))<0)
{
printf("fcntl operation error!\n");
exit(1);
}
printf("fcntl ret=%d\n",ret);
return ret;
}
/*-------------------------------------
clear oled with vertical addressing mode
--------------------------------------*/
void clearOledV(void)
{
int j;
//----set mode---
//-----set as vertical addressing mode -----
sendCmdOled(0x20); //set memory addressing mode
sendCmdOled(0x01); //[1:0]=00b-horizontal 01b-veritacal 10b-page addressing mode(RESET)
//---set column addr. for horizontal mode
sendCmdOled(0x21);
sendCmdOled(0);//column start
sendCmdOled(127);//column end, !!!! 8x16 for one line only!!!
//---set page addr.
sendCmdOled(0x22);
sendCmdOled(0);// 0-7 start page
sendCmdOled(7);// 2 rows. 2x8=16 !!!! for one line only!!!!
for(j=0;j<8*128;j++)
sendDatOled(0x00);
}
/*-----------------------------------
set display start line 0-63
-----------------------------------*/
void setStartLine(int k)
{
if(k>63)k=0;
sendCmdOled(0x40+k);
}
/*--------------------------------------
set vertical scrolling !!!!!---- has no effect of vertical scrolling, only horizontal scrolling.
---------------------------------------*/
void setVScroll(int n_top, int n_scroll)
{
sendCmdOled(0xA3); //-set vertical scroll area
sendCmdOled(n_top); //A[5:0] set No. of rows in top fixed area.
sendCmdOled(n_scroll); // B[6:0]
/*---note for 64d MUX-----
A[5:0]=0,B[6:0]=64; whole area scrolls
A[5:0]=0,B[6:0]<64; top area scrolls
A[5:0]+B[6:0]<64; central area scrolls
A[5:0]+B[6:0]=64; bottom area scrolls
--------------------------*/
}
//---- activate scroll -----
void actOledScroll(void)
{
sendCmdOled(0x2F);
}
//----- deactivate scroll -----
void deactOledScroll(void)
{
sendCmdOled(0x2E);
}