OLED Multi-Font IC Problems
Hello folks,
I have been working for some time now with the NHD-3.12-25664UMB3. It is a great display. However I have yet to be able to use the Multi-font functionality. I wrote a program based on the datasheets sample program, but nothing will display. Everything else in my program works and will display, but when it comes time to use the Multi-font IC the display stays blank. It was the main reason this display was chosen was to keep from having to write the code for multiple languages. Storing the Japanese or Chinese fonts takes up too much memory space in my PIC chip. I am using 4 wire SPI connection with a PIC18F. Below is the relevant code for those who are interested, but I have yet to get it to work. Does anyone have any suggestion to get it to work? Has anyone ever got it to work?
/*********************************************************************
Function Name: SetOLEDAddress
Return Value:
Parameters: oled_column, oled_row
Description: sets pointer to to write/read operations
********************************************************************/
void SetOLEDAddress(unsigned char x, unsigned char y){ //Starts at 0, 0 going to 255, 63
OLED_command(0x15); //column command
OLED_data(x);
OLED_data(0x77); //total columns divided by 2 (Default 77)
OLED_command(0x75); //row command
OLED_data(y);
OLED_data(0x7F); // default 7F
}
/*************************************************************
Function Name: Delay_ms
Return Value: void
Parameters: Number of milliseconds
Description: Delay function
TMR1 times out every ~170.666 us
**************************************************************/
void Delay_ms(long num_ms){ //JFR Used in the Key Scan function
long n;
for(n = 0; n < num_ms; n++){
INTCONbits.TMR0IF = 0; // Clear flag
TMR0H = 0xFC; //We only count from FC18h to FFFF
TMR0L = 0x1A; //Deducting one because each line takes time to execute also
while(!INTCONbits.TMR0IF); // Wait for timer flag to set
}
}
/******************************************************************
Function Name: OLED_char
Return Value:
Parameters: character, oled_column, oled_row
Description: Gets character data from the Multi-Font IC of the OLED Disable
******************************************************************/
void OLED_char (unsigned char character, unsigned char oled_column, unsigned char oled_row, char line){
unsigned char MSB, LSB, byte1, byte2, byte3;
unsigned char readByte, i;
unsigned char *readByte_ptr;
unsigned char FontBuffer[4][32]; //5 for 5 lines of text. 1-4 are the lines and 5 is going to be volume display characters
unsigned short long Address; //unsigned short long is 24-bits
//Need to split character into 2 8-bit words MSB and LSB
MSB = (character >> & 0xFF; //Could define each or the array as int or char or whatever
LSB = character & 0xFF;
//readByte_ptr = &readByte;
//Parameters: JIS0208 Japanese
//MSB: Higher byte of JIS code I think we should use Japanese JIS 0208
//LSB: Lower byte of JIS code This will include English and the Infinity symbol
//Address: Address of character data Note though ALL characters will be double height 15x16 pixels
if((MSB >= 1 && MSB <= 94) && (LSB >= 1 && LSB <= 94))
Address = (((((MSB - 1) * 94) + (LSB - 1)) * 32) + 490,624);
//To split the resulting number into bytes
byte1 = (Address >> 16) & 0xFF;
byte2 = (Address >> & 0xFF; //uses Bitwise AND to form 8-bit values
byte3 = Address & 0xFF; //source: https://stackoverflow.com/questions/3784263/converting-an-int-into-a-4-byte-char-array-c
//Send READ command and Address to Multi-Font IC.
OLEDen = 1;
MuFen = 0; //make rc5 of PIC18 go low to enable the Multi-Font IC
MultiFont_OUT(0x0B); //READ command This SPI_OUT is for the Multi-Font IC NOT the OLED
MultiFont_OUT(byte1); //Address Byte1 (MSB)
MultiFont_OUT(byte2); //Address Byte2
MultiFont_OUT(byte3); //Address Byte3 (LSB)
MultiFont_OUT(0xFF); //Dummy Byte Datasheet says 0x00, but their example has 0xFF
for(i = 0 ; i < 32 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 32.
FontBuffer[1] = MultiFont_IN(); //JFR Modified for testing!!!
}
MuFen = 1; //make rc5 of PIC18 go high to disable the Multi-Font IC
OLEDen = 0;
SetOLEDAddress(oled_column, oled_row); //set address location for font to be displayed
wram(); //Write to OLED Ram instruction
for(i = 0 ; i < 16 ; i++ ){ //for the first 16 bytes of font data
OLED_data(FontBuffer[1]); //write byte to display
oled_column++; //next byte will be for the next column
SetOLEDAddress(oled_column, oled_row); //set address location for next column
wram();
}
oled_column = oled_column - 16; //go back to first column of the font
oled_row = oled_row + 8; //move down to show the bottom half of font example had +16
SetOLEDAddress(oled_column, oled_row); //set address for bottom half of font
for(i = 16 ; i < 32 ; i++ ){ //for the second 16 bytes of font data
wram();
OLED_data(FontBuffer[1]); //write byte to display
oled_column++; //next byte will be for the next column
SetOLEDAddress(oled_column, oled_row); //set address location for next column
}
}
/******************************************************************
Function Name: display_oled_init
Return Value: 1 (used in main initialization routine)
Parameters: void
Description: Detects the OLED display and initializes it
*******************************************************************/
void display_oled_init(void)
{
unsigned char m;
unsigned int i;
unsigned char n;
unsigned char character;
unsigned char charcolumn;
unsigned char num_char = 16; //Maximum characters per line.
//Delay_ms(250);
//oled_setup();
int init_text[2][16] = {{0x2121, 0x2121, 0x2349, 0x236E, 0x2369, 0x2374, 0x2369, 0x2361, 0x236C, 0x2369, 0x237A, 0x2369, 0x236E, 0x2367, 0x2121, 0x2121},
{0x2121, 0x2350, 0x236C, 0x2365, 0x2361, 0x2373, 0x2365, 0x2124, 0x2121, 0x2377, 0x2361, 0x2369, 0x2374, 0x2125, 0x2121, 0x2121}};
//Displays 'Intializing' on line 2, and 'Please, wait.' on line 3.
//line 3 needs to be shifted by half a character to center under line 2.
SetOLEDAddress(0,16); //First the 'Initializing' line.
for(n = 0; n < num_char; n++){ //num_char should be changed to the exact number of characters in line_text
character = init_text[1][n]; //JFR Changed for testing!!!
charcolumn = (n * 16);
OLED_char(character, charcolumn, 16, 1);
}
//for(n = 0; n < num_char; n++){ //num_char should be changed to the exact number of characters in line_text
// character = init_text[0][n];
//OLED_char(character, 0, 32, 1);
//}
SetOLEDAddress(8,32); //Then the 'Please, wait.' line. Shift it right by half a charater. Thats 8 pixels.
//for(n = 0; n < num_char; n++){ //num_char should be changed to the exact number of characters in line_text
// character = init_text[1][n];
// OLED_char(character, 0, 16, 2);
//}
for(n = 0; n < num_char; n++){ //num_char should be changed to the exact number of characters in line_text
character = init_text[1][n];
OLED_char(character, 0, 32, 2);
}
//Would like to have these two lines centered. Can do this by adding blank spaces in front of each line.
Delay_ms(750);
//clear_oled_display(); //clears oled display
}
-
Well my good folks, I have figured this out on my own. Below are the relevant sections, but I will also post my full code for you to try! I am using a PIC18F26J50 for this project with a 16MHz crystal and NHD-2.8-25664UMB3 in 4 wire serial mode(SPI). It is compiled using Microchip's XC8 compiler. Hope this helps others! I know I wrestled with it for too long myself.
/******************************************************************
Function Name: OLED_Init
Return Value:
Parameters:
Description: Initializes OLED Display
******************************************************************/
void OLED_Init(void){
RES = 1;
Delay_ms(200);
RES = 0;
Delay_ms(750);
RES = 1;
Delay_ms(750);
comlock(0x12);
onoff(0x00);
column(0x1c,0x5B);
row(0x00,0x3f);
disclock(0x91);
ratio(0x3F);
offset(0x00);
start(0x00);
remap(0x14); /*set in Horizontal incriment mode aka Row Major Addressing*/
GPIO(0x00);
funsel(0x01);
disen(0xA0, 0xFD);
contrast(0x9F);
master(0x0F);
LGST();
phase(0xE2);
disenb(0x20);
prevolt(0x1F);
preper(0x08);
vcom(0x07);
mode(0x02);
partial(0x01, 0x00 ,0x00);
Clear_OLED();
onoff(0x01);
}
void column(unsigned char a, unsigned char b) { //
OLED_command(0x15); //Set Column Address
OLED_data(a); //Default - 00
OLED_data(b); //total columns divided by 2 (Default 77)
}
void row(unsigned char a, unsigned char b) { //
OLED_command(0x75); // Row Address
OLED_data(a); // default 00
OLED_data(b); // default 7F
}
void wram(void){ //Write to RAM command
OLED_command(0x5c);
}
/******************************************************************
Function Name: Clear_OLED
Return Value:
Parameters:
Description: Clears OLED display
******************************************************************/
void Clear_OLED(void) {
unsigned char i,j;
column(0x00,0x77);
row(0x00,0x7F);
wram();
for(i=0;i<64;i++){
for(j=0;j<120;j++){
OLED_data(0x00);
OLED_data(0x00);
}
for(j=0;j<120;j++){
OLED_data(0x00);
OLED_data(0x00);
}
}
}
/******************************************************************
Function Name: Data_processing
Return Value:
Parameters: temp
Description: turns 1byte B/W data to 4 btyes gray data for
display on OLED Display
******************************************************************/
void Data_processing(unsigned char temp){
switch(temp >> 6){ //Comes from New Haven Display sample code. Was in Image routine.
case 0:
OLED_data(0x00);
break;
case 1:
OLED_data(0x0F);
break;
case 2:
OLED_data(0xF0);
break;
case 3:
OLED_data(0xFF);
break;
default:
break;
}
switch((temp >> 4) & 0x03){
case 0:
OLED_data(0x00);
break;
case 1:
OLED_data(0x0F);
break;
case 2:
OLED_data(0xF0);
break;
case 3:
OLED_data(0xFF);
break;
default:
break;
}
switch((temp >> 2) & 0x03){
case 0:
OLED_data(0x00);
break;
case 1:
OLED_data(0x0F);
break;
case 2:
OLED_data(0xF0);
break;
case 3:
OLED_data(0xFF);
break;
default:
break;
}
switch((temp) & 0x03){
case 0:
OLED_data(0x00);
break;
case 1:
OLED_data(0x0F);
break;
case 2:
OLED_data(0xF0);
break;
case 3:
OLED_data(0xFF);
break;
default:
break;
}
}
/******************************************************************
Function Name: OLED_JIS0208
Return Value:
Parameters: character, oled_column, line
Description: Gets character data from the Multi-Font IC of the OLED Display
******************************************************************/
void OLED_JIS0208 (int character, unsigned char oled_column, char line){
unsigned char MSB, LSB, byte1, byte2, byte3;
unsigned char readByte, h, i, j, k, m, n;
unsigned char colSta, colFin, rowSta, rowFin;
unsigned char FontBuffer[32];
unsigned char RotatedFont[4][8];
unsigned char z = 0; //Make sure z always starts at 0.
unsigned long Address = 0; //unsigned long is 32-bits
//Need to split character into 2 8-bit words MSB and LSB
MSB = (character >> & 0xFF; //Could define each or the array as int or char or whatever
LSB = character & 0xFF;
MSB = MSB - 0x21; //Need to adjust to the reference of 0x0000 before the Address calculation
LSB = LSB - 0x21;
//Parameters: JIS0208 Japanese
//MSB: Higher byte of JIS code I think we should use Japanese JIS 0208
//LSB: Lower byte of JIS code This will include English and the Infinity symbol
//Address: Address of character data Note though ALL characters will be double height 15x16 pixels
//if((MSB >= 0x01 && MSB <= 0x5E) && (LSB >= 0x01 && LSB <= 0x5E)){
Address = MSB * 0x5E;
Address = Address + LSB;
Address = Address * 0x20;
Address = Address + 0x077C80;
//To split the resulting number into bytes
byte1 = (Address >> 16) & 0xFF;
byte2 = (Address >> & 0xFF; //uses bitshifting and Bitwise AND to form 8-bit values
byte3 = Address & 0xFF;
//Send READ command and Address to Multi-Font IC.
OLEDen = 1;
MuFen = 0; //make rc5 of PIC18 go low to enable the Multi-Font IC
MultiFont_OUT(0x0B); //READ command This SPI_OUT is for the Multi-Font IC NOT the OLED
MultiFont_OUT(byte1); //Address Byte1 (MSB)
MultiFont_OUT(byte2); //Address Byte2
MultiFont_OUT(byte3); //Address Byte3 (LSB)
MultiFont_OUT(0xFF); //Dummy Byte Datasheet says 0x00, but their example has 0xFF. 0xFF is Correct.
for(i = 0 ; i < 32 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 32.
FontBuffer = MultiFont_IN();
}
MuFen = 1; //make rc5 of PIC18 go high to disable the Multi-Font IC
OLEDen = 0;
//Need to Rotate the BitMap for each character couter-clockwise.
//To do this we will break the 16x16 image apart into 4 8x8 bit blocks.
//Image 0 is bytes 0-7. Image 1 is bytes 8-15.
//Image 2 is bytes 16-23. Image 3 is bytes 24-31.
for(m = 0; m < 4; m++){ //There are 4 8x8 bit blocks to be rotated
for(n = 0; n < 8; n++){ //Make sure the RotatedFont array is filled with 0.
RotatedFont[m][n] = 0; //m represents each image. n represents each byte in that image
}
}
for(h = 0; h < 4; h++) { //There are 4 8x8 bit blocks to be rotated.
for(k = 0; k < 8; k++) { //There are 8 bytes per image
for(j = 0; j < 8; j++) { //There are 8 bits per byte
if(FontBuffer[((h*+j)] & 1<<k){ //Use bitswise operations to break and reform the bytes
RotatedFont[h][k] |= 1<<(7-j); //And form it into an array
}
}
}
}
//End of rotate functions
rowSta = ((line-1)*16); //gives row value to lines starting with count 1.
colSta = oled_column + 28; //28 is the 0 column reference
colFin = colSta + 3; //Each character is 16 pixels wide or 2 double hex numbers. That is 4 columns. So colSta and 3 more.
rowFin = rowSta + 15; //Each character is 16 rows tall. So oled_row and 15 more.
column(colSta, colFin); //Set column address from Column Start to Column Finish
row(rowSta, rowFin); //Set row address from oled_row (the start row) to Row Finish
wram();
//Now we display the rotated image from the 2D array.
for(i = 0; i < 8; i++){ //We have two arrays of 8 1-byte characters each
Data_processing(RotatedFont[0]); //First the top half of the image
Data_processing(RotatedFont[1]); //We need Image0B0, Image1B0, Image0B1, Image1B1, Image0B2, ..., Image1B7
}
for(i = 0; i < 8; i++){ //Again we have two arrays of 8 1-byte characters each
//Now the bottom half of the image.
Data_processing(RotatedFont[2]); //We need Image2B0, Image3B0, Image2B1, Image3B1, Image2B2, ..., Image3B7
Data_processing(RotatedFont[3]);
}
}
/******************************************************************
Function Name: display_oled_init
Return Value: void
Parameters: void
Description: Detects the OLED display and initializes it
*******************************************************************/
void display_oled_init(void){
unsigned char m;
unsigned char q = 1;
unsigned char n;
unsigned short long character;
unsigned char charcolumn;
unsigned char num_char = 16; //Maximum characters per line.
Delay_ms(250);
OLED_Init();
int init_text[2][16] = {{0x2121, 0x2121, 0x2349, 0x236E, 0x2369, 0x2374, 0x2369, 0x2361, 0x236C, 0x2369, 0x237A, 0x2369, 0x236E, 0x2367, 0x2121, 0x2121},
{0x2121, 0x2350, 0x236C, 0x2365, 0x2361, 0x2373, 0x2365, 0x2124, 0x2121, 0x2377, 0x2361, 0x2369, 0x2374, 0x2125, 0x2121, 0x2121}};
//Displays 'Intializing' on line 2, and 'Please, wait.' on line 3.
//line 3 needs to be shifted by half a character to center under line 2.
for(m = 0; m < num_char; m++){ //num_char should be changed to the exact number of characters in line_text
charcolumn = (m * 4); //each nibble is a column, a byte is 2 columns. Each charater is 2 Bytes wide
OLED_JIS0208(init_text[0][m], charcolumn, 2);
charcolumn = charcolumn + 2; //Shifts charcolumn over by 2 columns (half a character width).
OLED_JIS0208(init_text[1][m], charcolumn, 3);
}
Delay_ms(1500);
Clear_OLED(); //clears oled display
}
/******************************************************************
Function Name: OLED_ASCII
Return Value:
Parameters: *pAscii, colS, rowS, FontType)
Description: displays ASCII characters in one of three font types
******************************************************************/
void OLED_ASCII (unsigned char *pAscii, unsigned char colS, unsigned char rowS, unsigned char FontType){
unsigned char readByte, h, i, j, k, m, n;
unsigned char RotatedFont[2][8];
unsigned char FontBuffer[16]; //characters have 8 bytes of data
unsigned long Address; //unsigned char is 8-bits or 1 byte, Address will be 3 bytes
unsigned char colF, rowF, block;
unsigned char MSB, LSB, byte1, byte2, byte3;
//Parameters: Ascii code
block = 1;
Address = (*pAscii - 0x20);
Address = Address * 8;
colF = colS + 1; //All 3 Font Types are 8-bits wide. Thats 2 columns.
if (FontType == 1){ //5x7 Font
rowF = rowS + 7; //Each 5x7 character covers 8x8 pixels. Thats 8 rows and 2 columns.
}
else if (FontType == 2){ //7x8 Font
Address = Address + 768;
rowF = rowS + 7; //Each 7x8 character covers 8x8 pixels. Thats 8 rows and 2 columns.
}
else if (FontType == 3){ //8x16 Font
Address = Address * 2;
Address = Address + 1536;
rowF = rowS + 15; //Each 8x16 character covers 8x16 pixels. Thats 16 rows and 2 columns.
block = 2;
}
//To split the resulting number into bytes
byte1 = (Address >> 16) & 0xFF;
byte2 = (Address >> & 0xFF; //uses bitshifting and Bitwise AND to form 8-bit values
byte3 = Address & 0xFF;
for(m = 0; m < 2; m++){ //There are 4 8x8 bit blocks to be rotated
for(n = 0; n < 8; n++){ //Make sure the Temp array is filled with 0.
RotatedFont[m][n] = 0; //m represents each image. n represents each byte in that image
}
}
//Send READ command and Address to Multi-Font IC.
OLEDen = 1;
MuFen = 0; //make rc5 of PIC18 go low to enable the Multi-Font IC
MultiFont_OUT(0x0B); //READ command This SPI_OUT is for the Multi-Font IC NOT the OLED
MultiFont_OUT(byte1); //Address Byte1 (MSB)
MultiFont_OUT(byte2); //Address Byte2
MultiFont_OUT(byte3); //Address Byte3 (LSB)
MultiFont_OUT(0xFF); //Dummy Byte Datasheet says 0x00, but their example has 0xFF. 0xFF is Correct.
if (block == 1){
for(i = 0 ; i < 8 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 8.
FontBuffer = MultiFont_IN(); //read one byte From the Multi-Font IC
}
}
else if (block == 2){
for(i = 0 ; i < 16 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 8.
FontBuffer = MultiFont_IN(); //read one byte From the Multi-Font IC
}
}
MuFen = 1; //make rc5 of PIC18 go high to disable the Multi-Font IC
OLEDen = 0;
//Need to rotate the character counter-clockwise
for(h = 0; h < block; h++) { //There are 4 8x8 bit blocks to be rotated.
for(k = 0; k < 8; k++) { //There are 8 bytes per image
for(j = 0; j < 8; j++) { //There are 8 bits per byte
if(FontBuffer[((h*+j)] & 1<<k){ //Use bitswise operations to break and reform the bytes
RotatedFont[h][k] |= 1<<(7-j); //And form it into an array
}
}
}
}
//End of rotate functions
column(colS, colF); //Set column address from Column Start to Column Finish
row(rowS, rowF); //Set row address from oled_row (the start row) to Row Finish
wram();
for(h = 0; h < block; h++) {
for(i = 0 ; i < 8 ; i++ ){ //for the 8 bytes of font data
Data_processing(RotatedFont[h]); //write byte to display
}
}
}
/******************************************************************
Function Name: OLED_String
Return Value:
Parameters: *pStr, colS, rowS, FontType)
Description: displays a string of ASCII characters in one of three font types
******************************************************************/
void OLED_String(unsigned char *pStr, unsigned char col, unsigned char rowS, unsigned char FontType){
unsigned char colS;
colS = col + 28; //28 is the 0 column reference
while(1)
{
if (*pStr == 0)
{
return;
}
OLED_ASCII (pStr, colS, rowS, FontType);
colS += 2;
pStr += 1;
}
}0 -
As promised, here is the complete code! It is split in 2 parts due to size limitations of attachments. Also NHD does not allow txt or c files to be attached, so I have it in pdf files. Again I am using a PIC18F26J50 for this project with a 16MHz crystal and NHD-2.8-25664UMB3 in 4 wire serial mode(SPI). It is compiled using Microchip's XC8 compiler.
Part 2 to follow!0 -
Here is Part 2!
1
2 /*************************************************************
3 ************END*OLED*INITIALIZATION*FUNCTIONS*****************
4 *************************************************************/
5
6
7 void disp(void){ //appears to be a checkerboard pattern display
8 unsigned char i,j;
9
10 column(0x00,0x77);
11 row(0x00,0x7F);
12 wram();
13
14 for(i=0;i<64;i++){
15 for(j=0;j<120;j++){
16 OLED_data(0xF0);
17 OLED_data(0xF0);
18 }
19 for(j=0;j<120;j++){
20 OLED_data(0x0F);
21 OLED_data(0x0F);
22 }
23 }
24 }
25
26
27 /******************************************************************
28 Function Name: Clear_OLED
29 Return Value:
30 Parameters:
31 Description: Clears OLED display
32 ******************************************************************/
33 void Clear_OLED(void) {
34 unsigned char i,j;
35
36 column(0x00,0x77);
37 row(0x00,0x7F);
38 wram();
39
40 for(i=0;i<64;i++){
41 for(j=0;j<120;j++){
42 OLED_data(0x00);
43 OLED_data(0x00);
44 }
45 for(j=0;j<120;j++){
46 OLED_data(0x00);
47 OLED_data(0x00);
48 }
49 }
50 }
51
52
53 /******************************************************************
54 Function Name: Data_processing
55 Return Value:
56 Parameters: temp
57 Description: turns 1byte B/W data to 4 btyes gray data for
58 display on OLED Display
59 ******************************************************************/
60 void Data_processing(unsigned char temp){
61
62 switch(temp >> 6){ //Comes from New Haven Display sample code. Was in Image routine.
63 case 0:
64 OLED_data(0x00);
65 break;
66 case 1:
67 OLED_data(0x0F);
68 break;
69 case 2:
70 OLED_data(0xF0);
71 break;
72 case 3:
73 OLED_data(0xFF);
74 break;
75 default:
76 break;
77 }
78
79 switch((temp >> 4) & 0x03){
80 case 0:
81 OLED_data(0x00);
82 break;
83 case 1:
84 OLED_data(0x0F);
85 break;
86 case 2:
87 OLED_data(0xF0);
88 break;
89 case 3:
90 OLED_data(0xFF);
91 break;
92 default:
93 break;
94 }
95
96 switch((temp >> 2) & 0x03){
97 case 0:
98 OLED_data(0x00);
99 break;
100 case 1:
101 OLED_data(0x0F);
102 break;
103 case 2:
104 OLED_data(0xF0);
105 break;
106 case 3:
107 OLED_data(0xFF);
108 break;
109 default:
110 break;
111 }
112
113 switch((temp) & 0x03){
114 case 0:
115 OLED_data(0x00);
116 break;
117 case 1:
118 OLED_data(0x0F);
119 break;
120 case 2:
121 OLED_data(0xF0);
122 break;
123 case 3:
124 OLED_data(0xFF);
125 break;
126 default:
127 break;
128 }
129 }
130
131
132 /******************************************************************
133 Function Name: Image
134 Return Value:
135 Parameters: array[]
136 Description: Displays image contained in bitmaped array using
137 the full 64x256 pixels of OLED Display
138 ******************************************************************/
139 void Image(const unsigned char array[]){
140 int i;
141 column(28,91);
142 row(0,63);
143 wram();
144
145 for(i = 0; i < 2048; i++){ //We have (64 rows)(64 columns)/(2 bytes)= 2048 hex characters in our array
146 Data_processing(array[i]);
147 }
148
149 }
150
151
152 /******************************************************************
153 Function Name: Delay_ms
154 Return Value:
155 Parameters: num_ms
156 Description: Creates a millisecond delay
157 ******************************************************************/
158 void Delay_ms(long num_ms){
159 long n;
160
161 for(n = 0; n < num_ms; n++){
162 INTCONbits.TMR0IF = 0; //Clear flag
163 TMR0H = 0xFC; //We only count from FC18h to FFFF
164 TMR0L = 0x1A; //Deducting one because each line takes time to execute also
165 while(!INTCONbits.TMR0IF); //Wait for timer flag to set
166 }
167 }
168
169
170 /******************************************************************
171 Function Name: OLED_JIS0208
172 Return Value:
173 Parameters: character, oled_column, line
174 Description: Gets character data from the Multi-Font IC of the OLED Display
175 ******************************************************************/
176 void OLED_JIS0208 (int character, unsigned char oled_column, char line){
177
178 unsigned char MSB, LSB, byte1, byte2, byte3;
179 unsigned char readByte, h, i, j, k, m, n;
180 unsigned char colSta, colFin, rowSta, rowFin;
181 unsigned char FontBuffer[32];
182 unsigned char RotatedFont[4][8];
183 unsigned char z = 0; //Make sure z always starts at 0.
184
185 unsigned long Address = 0; //unsigned long is 32-bits
186
187 //Need to split character into 2 8-bit words MSB and LSB
188 MSB = (character >> 8) & 0xFF; //Could define each or the array as int or char or whatever
189 LSB = character & 0xFF;
190
191 MSB = MSB - 0x21; //Need to adjust to the reference of 0x0000 before the Address calculation
192 LSB = LSB - 0x21;
193
194 //Parameters: JIS0208 Japanese
195 //MSB: Higher byte of JIS code I think we should use Japanese JIS 0208
196 //LSB: Lower byte of JIS code This will include English and the Infinity symbol
197 //Address: Address of character data Note though ALL characters will be double height 15x16 pixels
198 //if((MSB >= 0x01 && MSB <= 0x5E) && (LSB >= 0x01 && LSB <= 0x5E)){
199
200 Address = MSB * 0x5E;
201 Address = Address + LSB;
202 Address = Address * 0x20;
203 Address = Address + 0x077C80;
204
205
206 //To split the resulting number into bytes
207 byte1 = (Address >> 16) & 0xFF;
208 byte2 = (Address >> 8) & 0xFF; //uses bitshifting and Bitwise AND to form 8-bit values
209 byte3 = Address & 0xFF;
210
211 //Send READ command and Address to Multi-Font IC.
212 OLEDen = 1;
213 MuFen = 0; //make rc5 of PIC18 go low to enable the Multi-Font IC
214 MultiFont_OUT(0x0B); //READ command This SPI_OUT is for the Multi-Font IC NOT the OLED
215 MultiFont_OUT(byte1); //Address Byte1 (MSB)
216 MultiFont_OUT(byte2); //Address Byte2
217 MultiFont_OUT(byte3); //Address Byte3 (LSB)
218 MultiFont_OUT(0xFF); //Dummy Byte Datasheet says 0x00, but their example has 0xFF. 0xFF is Correct.
219
220 for(i = 0 ; i < 32 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 32.
221 FontBuffer[i] = MultiFont_IN();
222 }
223
224 MuFen = 1; //make rc5 of PIC18 go high to disable the Multi-Font IC
225 OLEDen = 0;
226
227 //Need to Rotate the BitMap for each character couter-clockwise.
228 //To do this we will break the 16x16 image apart into 4 8x8 bit blocks.
229 //Image 0 is bytes 0-7. Image 1 is bytes 8-15.
230 //Image 2 is bytes 16-23. Image 3 is bytes 24-31.
231 for(m = 0; m < 4; m++){ //There are 4 8x8 bit blocks to be rotated
232 for(n = 0; n < 8; n++){ //Make sure the RotatedFont array is filled with 0.
233 RotatedFont[m][n] = 0; //m represents each image. n represents each byte in that image
234 }
235 }
236
237 for(h = 0; h < 4; h++) { //There are 4 8x8 bit blocks to be rotated.
238 for(k = 0; k < 8; k++) { //There are 8 bytes per image
239 for(j = 0; j < 8; j++) { //There are 8 bits per byte
240
241 if(FontBuffer[((h*8)+j)] & 1<<k){ //Use bitswise operations to break and reform the bytes
242 RotatedFont[h][k] |= 1<<(7-j); //And form it into an array
243 }
244
245 }
246 }
247 }
248
249 //End of rotate functions
250
251 rowSta = ((line-1)*16); //gives row value to lines starting with count 1.
252
253 colSta = oled_column + 28; //28 is the 0 column reference
254 colFin = colSta + 3; //Each character is 16 pixels wide or 2 double hex numbers. That is 4 columns. So colSta and 3 more.
255
256 rowFin = rowSta + 15; //Each character is 16 rows tall. So oled_row and 15 more.
257
258 column(colSta, colFin); //Set column address from Column Start to Column Finish
259 row(rowSta, rowFin); //Set row address from oled_row (the start row) to Row Finish
260
261 wram();
262
263 //Now we display the rotated image from the 2D array.
264 for(i = 0; i < 8; i++){ //We have two arrays of 8 1-byte characters each
265
266 Data_processing(RotatedFont[0][i]); //First the top half of the image
267 Data_processing(RotatedFont[1][i]); //We need Image0B0, Image1B0, Image0B1, Image1B1, Image0B2, ..., Image1B7
268 }
269
270 for(i = 0; i < 8; i++){ //Again we have two arrays of 8 1-byte characters each
271 //Now the bottom half of the image.
272 Data_processing(RotatedFont[2][i]); //We need Image2B0, Image3B0, Image2B1, Image3B1, Image2B2, ..., Image3B7
273 Data_processing(RotatedFont[3][i]);
274 }
275 }
276
277
278 /******************************************************************
279 Function Name: display_oled_init
280 Return Value: void
281 Parameters: void
282 Description: Detects the OLED display and initializes it
283 *******************************************************************/
284 void display_oled_init(void){
285
286 unsigned char m;
287 unsigned char q = 1;
288 unsigned char n;
289 unsigned short long character;
290 unsigned char charcolumn;
291 unsigned char num_char = 16; //Maximum characters per line.
292
293 //Delay_ms(250);
294
295 //OLED_Init();
296
297 int init_text[2][16] = {{0x2121, 0x2121, 0x2349, 0x236E, 0x2369, 0x2374, 0x2369, 0x2361, 0x236C, 0x2369, 0x237A, 0x2369, 0x236E, 0x2367, 0x2121, 0x2121},
298 {0x2121, 0x2350, 0x236C, 0x2365, 0x2361, 0x2373, 0x2365, 0x2124, 0x2121, 0x2377, 0x2361, 0x2369, 0x2374, 0x2125, 0x2121, 0x2121}};
299 //Displays 'Intializing' on line 2, and 'Please, wait.' on line 3.
300 //line 3 needs to be shifted by half a character to center under line 2.
301
302 for(m = 0; m < num_char; m++){ //num_char should be changed to the exact number of characters in line_text
303
304 charcolumn = (m * 4); //each nibble is a column, a byte is 2 columns. Each charater is 2 Bytes wide
305 OLED_JIS0208(init_text[0][m], charcolumn, 2);
306 charcolumn = charcolumn + 2; //Shifts charcolumn over by 2 columns (half a character width).
307 OLED_JIS0208(init_text[1][m], charcolumn, 3);
308 }
309
310 //Would like to have these two lines centered. Can do this by adding blank spaces in front of each line.
311 Delay_ms(1500);
312
313 Clear_OLED(); //clears oled display
314 }
315
316
317 /******************************************************************
318 Function Name: OLED_ASCII
319 Return Value:
320 Parameters: *pAscii, colS, rowS, FontType)
321 Description: displays ASCII characters in one of three font types
322 ******************************************************************/
323 void OLED_ASCII (unsigned char *pAscii, unsigned char colS, unsigned char rowS, unsigned char FontType){
324
325 unsigned char readByte, h, i, j, k, m, n;
326 unsigned char RotatedFont[2][8];
327 unsigned char FontBuffer[16]; //characters have 8 bytes of data
328 unsigned long Address; //unsigned char is 8-bits or 1 byte, Address will be 3 bytes
329 unsigned char colF, rowF, block;
330 unsigned char MSB, LSB, byte1, byte2, byte3;
331
332 //Parameters: Ascii code
333 block = 1;
334
335 Address = (*pAscii - 0x20);
336 Address = Address * 8;
337 colF = colS + 1; //All 3 Font Types are 8-bits wide. Thats 2 columns.
338
339 if (FontType == 1){ //5x7 Font
340 rowF = rowS + 7; //Each 5x7 character covers 8x8 pixels. Thats 8 rows and 2 columns.
341 }
342
343 else if (FontType == 2){ //7x8 Font
344 Address = Address + 768;
345 rowF = rowS + 7; //Each 7x8 character covers 8x8 pixels. Thats 8 rows and 2 columns.
346 }
347
348 else if (FontType == 3){ //8x16 Font
349 Address = Address * 2;
350 Address = Address + 1536;
351 rowF = rowS + 15; //Each 8x16 character covers 8x16 pixels. Thats 16 rows and 2 columns.
352 block = 2;
353 }
354
355
356 //To split the resulting number into bytes
357 byte1 = (Address >> 16) & 0xFF;
358 byte2 = (Address >> 8) & 0xFF; //uses bitshifting and Bitwise AND to form 8-bit values
359 byte3 = Address & 0xFF;
360
361
362 for(m = 0; m < 2; m++){ //There are 4 8x8 bit blocks to be rotated
363 for(n = 0; n < 8; n++){ //Make sure the Temp array is filled with 0.
364 RotatedFont[m][n] = 0; //m represents each image. n represents each byte in that image
365 }
366 }
367
368 //Send READ command and Address to Multi-Font IC.
369 OLEDen = 1;
370 MuFen = 0; //make rc5 of PIC18 go low to enable the Multi-Font IC
371 MultiFont_OUT(0x0B); //READ command This SPI_OUT is for the Multi-Font IC NOT the OLED
372 MultiFont_OUT(byte1); //Address Byte1 (MSB)
373 MultiFont_OUT(byte2); //Address Byte2
374 MultiFont_OUT(byte3); //Address Byte3 (LSB)
375 MultiFont_OUT(0xFF); //Dummy Byte Datasheet says 0x00, but their example has 0xFF. 0xFF is Correct.
376
377 if (block == 1){
378 for(i = 0 ; i < 8 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 8.
379 FontBuffer[i] = MultiFont_IN(); //read one byte From the Multi-Font IC
380 }
381 }
382
383 else if (block == 2){
384 for(i = 0 ; i < 16 ; i++ ){ //For i number of bytes to gather from Multi-Font IC. In this case its 8.
385 FontBuffer[i] = MultiFont_IN(); //read one byte From the Multi-Font IC
386 }
387 }
388
389 MuFen = 1; //make rc5 of PIC18 go high to disable the Multi-Font IC
390 OLEDen = 0;
391
392 //Need to rotate the character counter-clockwise
393 for(h = 0; h < block; h++) { //There are 4 8x8 bit blocks to be rotated.
394 for(k = 0; k < 8; k++) { //There are 8 bytes per image
395 for(j = 0; j < 8; j++) { //There are 8 bits per byte
396
397 if(FontBuffer[((h*8)+j)] & 1<<k){ //Use bitswise operations to break and reform the bytes
398 RotatedFont[h][k] |= 1<<(7-j); //And form it into an array
399 }
400
401 }
402 }
403 }
404 //End of rotate functions
405
406 column(colS, colF); //Set column address from Column Start to Column Finish
407 row(rowS, rowF); //Set row address from oled_row (the start row) to Row Finish
408
409 wram();
410
411 for(h = 0; h < block; h++) {
412 for(i = 0 ; i < 8 ; i++ ){ //for the 8 bytes of font data
413 Data_processing(RotatedFont[h][i]); //write byte to display
414 }
415 }
416 }
417
418
419 /******************************************************************
420 Function Name: OLED_String
421 Return Value:
422 Parameters: *pStr, colS, rowS, FontType)
423 Description: displays a string of ASCII characters in one of three font types
424 ******************************************************************/
425 void OLED_String(unsigned char *pStr, unsigned char col, unsigned char rowS, unsigned char FontType){
426
427 unsigned char colS;
428
429 colS = col + 28; //28 is the 0 column reference
430 while(1)
431 {
432 if (*pStr == 0)
433 {
434 return;
435 }
436
437 OLED_ASCII (pStr, colS, rowS, FontType);
438 colS += 2;
439 pStr += 1;
440
441 }
442 }
443
444
445 /******************************************************************
446 Function Name: PICinit
447 Return Value:
448 Parameters:
449 Description: Initializes PIC18F
450 ******************************************************************/
451 static void PICinit(void) {
452
453 OSCTUNE = 0x40; //enable the 96MHz PLL
454
455 //PORTA: all inputs, no interrupt-on-change facility
456 //PORTA = 0;
457 PORTA = 0x00;
458 TRISA = 0xFF; //A all inputs
459 ADCON0 = 0;
460 ANCON0 = 0xFF;
461 ANCON1 = 0x1F; //disable AD converter, all digital IO
462
463 //PORTB: use all-input config, use open-drain output style
464 //The I2C pins must also be configured in input mode.
465 //There is an Errata for several PIC18F devices, saying
466 //that a more extensive reset is needed for I2C operation
467 //TRISB = 0xCF; //1. first make I2C SDA and SCL as output
468 //Only for SPI on MSSP2!!!
469 //TRISBbits.RB0 = 0xFF; // 2.now make all pins inputs
470 PORTB = 0x00;
471 LATBbits.LATB1 = 0; //SPI2 Clock
472 LATBbits.LATB2 = 0; //SPI2 Data Output
473 TRISBbits.TRISB2 = 0; //SPI2 Data Output
474 TRISBbits.TRISB1 = 0; //SPI2 Clock
475 TRISBbits.TRISB0 = 1; //SPI2 Data Input
476
477 //PORTC: all output
478 PORTC = 0x00;
479 LATC = 0x00;
480 TRISC = 0x00;
481
482 //setup the remappable peripheral inputs:
483 //Clear IOLOCK
484 INTCONbits.GIE = 0;
485 EECON2 = 0x55;
486 EECON2 = 0xAA;
487 PPSCONbits.IOLOCK = 0;
488 RPINR21 = 0x03; //SPI2 Data Input -> RP3 ->RB0
489 RPINR22 = 0x04; //SPI2 Clock Input -> RP4 ->RB1
490 RPINR23 = 0x06; //SPI2 Slave Select -> RP6 ->RB3
491 RPOR4 = 0x0A; //SPI2 Clock Output -> RP4 ->RB1
492 RPOR5 = 0x09; //SPI2 Data Output -> RP5 ->RB2
493 // Set IOLOCK
494 EECON2 = 0x55;
495 EECON2 = 0xAA;
496 PPSCONbits.IOLOCK = 1;
497 INTCONbits.GIE = 1;
498
499 //Timer0 OK for use, 8-bit prescale, 8- or 16-bit counter, sets TMR0IF
500 //Timer1: enabling it locks pins RC0 and RC1 to a special-function input, cannot do that.
501 //Timer2: 4-prescale, 4-bit post-scale, 8-bit counter&comparator, sets TMR2IF
502 //Timer3: 3-bit prescale, 16-bit counter, allows cascading with TMR1 or TMR2
503 //Timer4: 4-bit prescale, 8-bit count&compare, 4=bit postscale, sets TMR4IF
504
505 //setup Timer0 for keypad delay_ms: 4x downscale from Fosc/4 is 1MHz
506 T0CON = 0x83; //Timer0 on, 16-bit mode, 16x prescale, on Fosc/4=4Mhz gives 1MHz= 1usec timer count
507 INTCON2bits.TMR0IP = 1; //high priority interrupt
508 INTCONbits.TMR0IE = 0; //for now, enabled on actual IR reception
509
510 //SPI2 Master to drive EEPROM and Display
511 //LATBbits.LATB1 = 0;
512 //TRISBbits.TRISB1 = 0; //SCK set as output
513 //TRISBbits.TRISB0 = 1; //SDI set as input
514 //TRISBbits.TRISB2 = 0; //SDO set as output
515 SSP2STAT = 0x00; //power on state
516 SSP2CON1 = 0x10; //power on state, synchronous enabled, clock idle low, clock=Fosc/4
517 SSP2CON1bits.SSPEN = 1;
518
519 //Set-up HVLD module: mute audio when power-supply unexpectedly drops
520 //Programmed HVLD value '1001' corresponds to 2.6V (range 2.47 - 2.73)
521 //Take a small safety margin on that voltage level,
522 //choosing it too low, can cause a too late audio mute.
523 //(in time is as long as the audio opamps have reasonable supply voltage)
524 HLVDCON = 0x79;
525 PIR2bits.LVDIF = 0;
526 IPR2bits.LVDIP = 1;
527 PIE2bits.LVDIE = 0; //Enable only after power has stabelized
528 }
529
530 /*************************************************************
531 **********************MAIN*FUNCTIONS**************************
532 *************************************************************/
533 void main(void) {
534
535 unsigned char str[24];
536
537 PICinit();
538 Delay_ms(1000);
539 init1();
540 Delay_ms(500);
541
542 while(1){
543 display_oled_init(); //uses Multi-Font IC.
544 Delay_ms(10); //clears itself!
545
546 Delay_ms(2500);
547 Clear_OLED();
548 Delay_ms(10);
549
550 OLED_JIS0208(0x4976, 4, 3); //Used to check address. Displays one kanji.
551 Delay_ms(1000);
552 Clear_OLED();
553 Delay_ms(10);
554
555 OLED_String("Hello!", 0, 0, 1);
556 OLED_String("This is a test", 0, 16, 2);
557 OLED_String("Showing three fonts", 0, 32, 3);
558 Delay_ms(3000);
559 Clear_OLED();
560 Delay_ms(10);
561
562 disp(); //displays tiny checkerboard pattern
563 Delay_ms(1000);
564 Clear_OLED();
565 Delay_ms(10);
566
567 Image(NHD25664test); //Image does display
568 Delay_ms(700);
569 Clear_OLED();
570 Delay_ms(10);
571 }
572 }« Last Edit: November 13, 2017, 01:16:45 AM by Kon-L »0 -
Hi,
Displays built-in IC controllers have limited functionalities comparing their own original version because they have some of their original pins wired to a certain configuration. You can guess such configuration by comparing the original controller pin-out and the display pin-out.
Understanding the IC controller built-in configuration is the first step before coding the display initialization.
You can find the display specs at https://newhavendisplay.com/content/specs/NHD-3.12-25664UMB3.pdf and the original IC specs at http://www.displayfuture.com/Display/datasheet/controller/SSD1322.pdf .
Anyway it's always good fun playing with displays.
Good luck!0
Please sign in to leave a comment.
Comments
4 comments