• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Testing I2C to run an SSD1306 OLED display with PIC16F1938

Vizier87

Active Member
Hi guys, been a while.

I'm attempting to run an SSD1306 display with this tutorial. The programs compiled pretty ok I guess. The PIC I'm using is PIC16F1938.

The display I'm using didn't have the RST/CS pins. Only SCL, SDA, Vcc and GND pins.

Here's the code:

C:
/**************************************************************************************

  Interfacing PIC16F887 microcontroller with SSD1306 OLED display
  C Code for mikroC PRO for PIC compiler
  Internal oscillator used @ 8MHz
  Configuration words: CONFIG1 = 0x2CD4
                       CONFIG2 = 0x0700
  This is a free software with NO WARRANTY.
  http://simple-circuit.com/

***************************************************************************************/

// define SSD1306 reset pin (if available)
//#define SSD1306_RST       RD4_bit
//#define SSD1306_RST_DIR   TRISD4_bit

#include <SSD1306.c>     // include SSD1306 OLED driver source file

char *text = "000\0";     // '\0' is the string terminator
unsigned short i = 0;

int i_= 0;
sbit Indicator at rb4_bit;

void Alert (unsigned int z){
    for (i_ = 0; i_ < z; i_++){
       Indicator = 1;
       Delay_ms(1000);
       Indicator = 0;
       Delay_ms(1000);
    }
    Indicator = 0;
}



void main() {
 
  trisb4_bit = 0;
  Alert(3);
  trisc = 0;
  portc = 0;

  delay_ms(500);   // wait half a second

  I2C1_Init(400000);    // initialize I2C communication with clock frequency of 400KHz

  // initialize the SSD1306 OLED with an I2C addr = 0x7A (default address)
  SSD1306_Init(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);

  // clear the screen
  SSD1306_ClearDisplay();

  SSD1306_GotoXY(1, 1);    // move cursor to column 1, row 1
  SSD1306_Print("Interfacing PIC16F887 with SSD1306 OLED display");  // print text
  delay_ms(5000);   // wait 5 seconds

  // clear the screen
  SSD1306_ClearDisplay();

  SSD1306_GotoXY(6, 2);   // move cursor to column 6, row 2
  SSD1306_Print("Hello world!");
  delay_ms(2000);

  SSD1306_StartScrollRight(1, 1);
  delay_ms(3000);
  SSD1306_StopScroll();

  SSD1306_StartScrollLeft(1, 1);
  delay_ms(3000);
  SSD1306_StopScroll();

  SSD1306_StartScrollDiagRight(1, 1);
  delay_ms(3000);
  SSD1306_StopScroll();

  SSD1306_StartScrollDiagLeft(1, 1);
  delay_ms(3000);
  SSD1306_StopScroll();

  delay_ms(3000);
  SSD1306_ClearDisplay();

  SSD1306_GotoXY(6, 2);
  SSD1306_Print("Hello world!");
  delay_ms(2000);

  while(1) {

    text[0] = (i / 100) % 10 + '0';   // extract hundreds digit
    text[1] = (i / 10)  % 10 + '0';   // extract tens digit
    text[2] =  i        % 10 + '0';   // extract ones digit

    SSD1306_GotoXY(10, 5);
    SSD1306_Print(text);

    i += 1;   // increment i

    delay_ms(500);

  }

}
// End of code.
After compiling and burning the .HEX, didn't work. That's fine, troubleshooting then.

Then I checked RC3 and RC4 with a scope. No signals/clocked output observed, just a DC output.

So I tried checked the I2C hardware by a simple library code:

C:
void main(){
  trisc = 0;
  portc = 0;
  PORTB = 0;
  TRISB = 0;                 // Configure PORTB as output
  I2C1_Init(100000);         // initialize I2C communication
  I2C1_Start();              // issue I2C start signal
  I2C1_Wr(0xA2);             // send byte via I2C  (device address + W)
  I2C1_Wr(2);                // send byte (address of EEPROM location)
 
 
  while (1){
     I2C1_Wr(0xAA);             // send data (data to be written)
     I2C1_Stop();               // issue I2C stop signal  Delay_100ms();
     I2C1_Start();              // issue I2C start signal
     I2C1_Wr(0xA2);             // send byte via I2C  (device address + W)
     I2C1_Wr(2);                // send byte (data address)
     I2C1_Repeated_Start();     // issue I2C signal repeated start
     I2C1_Wr(0xA3);             // send byte (device address + R)
     PORTB = I2C1_Rd(0u);       // Read the data (NO acknowledge)
     I2C1_Stop();               // issue I2C stop signal
 
  }

 
}
And no clocked signals either from RC3 or RC4.

Anyone can point me in the right direction here?

Thanks.
Vizier87
 

Vizier87

Active Member
Do you have the "pullups" in place.. I normally use 4k7 as the sda and sck lines are high impedance the lines are just pulled low...
Hi Ian! Nice to see you're still running ETO.
So the "pullups" are to the Vcc right? I didn't do it because the schematics didn't specify that part. Ok will do it soon and report the results.

Thanks!
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Hi Ian! Nice to see you're still running ETO.
Not quite!! Just helping out..

Pullups can be different values.. All depends on how many devices are on the bus... 2k7 ~ 10k are normal... I found 4k7 works for me..
 

Nigel Goodwin

Super Moderator
Most Helpful Member
Not quite!! Just helping out..

Pullups can be different values.. All depends on how many devices are on the bus... 2k7 ~ 10k are normal... I found 4k7 works for me..
As you say, they aren't at all critical - I usually use 10k these days - but that could just be because I have a bandolier of 2000 of them! :D

My PIC tutorials used 12K - again, simply because they were to hand.
 

Mike - K8LH

Well-Known Member
All of the 0.91" (128x32) and 0.96" (128x64) displays I've purchased had built-in pull-ups.

Which display are you using?
 
Last edited:

Vizier87

Active Member
Not quite!! Just helping out..

Pullups can be different values.. All depends on how many devices are on the bus... 2k7 ~ 10k are normal... I found 4k7 works for me..
Ian, anyhow, with the hardware I2C code and pullup resistors (I used 1k ohm), it just still shows a DC signal. I think my configuration is messed up somewhere? Both RC3 and RC4 (SDA & SCL) pins are giving the DC output.


All of the 0.91" (128x32) and 0.96" (128x64) displays I've purchased had built-in pull-ups.

Which display are you using?
Hehe I'm not really sure. Got it from a friend. Here's how it looks like:

thumbnail.jpg

I think it's the 128x64? The glass part measures 2cm x 2.7 cm.

I believe it has to be my configuration settings but I'm not sure. Here's the settings:
1573357126364.png


Is there anything I might have missed? I'd like to just test if the hardware I2C is even giving out any clocked signals at the first place. I've tweaked a bit here and there and it didn't seem to change anything. The SCL is RC3 and SDA at RC4. The code is at the first post.

As per the PIC16F1938's pins, I can see a nice clock if I just do a simple 1010101 loop at 10us.

1573357488942.png

So I don't think the pin is damaged.

What else do I have to check?
Thanks,
Vizier87
 

Pommie

Well-Known Member
Most Helpful Member
Both RC3 and RC4 (SDA & SCL) pins are giving the DC output.
What DC output? If it's zero then a device may be holding the bus low (clock stretching). This can happen when I²C communication is interrupted when you compile.

Mike.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Hi Mike. The DC output is constantly HI at ~4.5V.
It will be... It would appear that the I2C output isn't where you think it is That chip has analogue segment out for LCD's... Just check if it needs turning off..
 

Vizier87

Active Member
It will be... It would appear that the I2C output isn't where you think it is That chip has analogue segment out for LCD's... Just check if it needs turning off..
Hi Ian, I've attempted to tweak like the following:

C:
void main(){
  LCDEN_bit = 0;
  LCDIRE_bit = 0;
  LCDREF = 0;
  LCDSE1 = 0;
  LCDSE0 = 0;
  SSPEN_bit = 1;

  ansela = 0;
  anselb = 0;

  trisc = 0;
  portc = 0;


  I2C1_Init(100000);         // initialize I2C communication
  I2C1_Start();              // issue I2C start signal
  while (1){
     I2C1_Wr(0xff);             // send byte via I2C  (device address + W)
  }
 
}
And still nothing else. I'm not sure if I'm doing this correctly though.. I just saw that the control bits/registers might have something to do with the I2C pins but I'm like shooting in the dark here.

What do you think? Here are the registers which might be associated as per the datasheet:
1573438127956.png
 

rjenkinsgb

Well-Known Member
Most Helpful Member
Just a thought - the example project was for the 877, you are using the 1938.

Have you changed the MCU type in the overall compiler project settings? The addresses for peripheral control registers are very different between the two devices.
 

Vizier87

Active Member
Just a thought - the example project was for the 877, you are using the 1938.

Have you changed the MCU type in the overall compiler project settings? The addresses for peripheral control registers are very different between the two devices.
Yeah, I have. I'm using MikroC so the configuration settings are way easier. Just select the settings we want from Project Settings.
 

Vizier87

Active Member
Try setting it up using MCC, that should set whatever needs doing (hopefully), otherwise read the datasheet.
Hi Uncle Nigel. I've been reading the datasheet. Unfortunately the key to understanding the peripherals is also my weakness - the block diagrams are a bit enigmatic for me.

Otherwise I have been using PIC for quite a long time. Not intense enough for it to be a career though.

So MCC is this one right?
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Try setting it up using MCC, that should set whatever needs doing (hopefully), otherwise read the datasheet.
Sorry Nigel... MikroC isn't ANSI C its its own abomination.. Code configurator is a long way off..

Vizier87 The ports are in the datasheet, but If it has a LCDEN points to it not being that.. PORTC 3 and 2 should be configured as input!!! They HAVE to be high impedance..
 

Vizier87

Active Member
Sorry Nigel... MikroC isn't ANSI C its its own abomination.. Code configurator is a long way off..

Vizier87 The ports are in the datasheet, but If it has a LCDEN points to it not being that.. PORTC 3 and 2 should be configured as input!!! They HAVE to be high impedance..
So if I want to make sure the i2c output is enabled, I have to configure LCDEN as 0? Sorry not so clear..
 

Nigel Goodwin

Super Moderator
Most Helpful Member
Sorry Nigel... MikroC isn't ANSI C its its own abomination.. Code configurator is a long way off..

Vizier87 The ports are in the datasheet, but If it has a LCDEN points to it not being that.. PORTC 3 and 2 should be configured as input!!! They HAVE to be high impedance..
Worth installing MPLABX and MCC just to use the MCC, he can always nick the setup routines if he really wants to continue with MicroC.
 

Pommie

Well-Known Member
Most Helpful Member
Sorry but I really detest MCC. It produces incomprehensible nonsense. I'd rather spend the time going through the datasheet and write my own. However, never used anything more powerful than an 18 series.

Mike.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Port C sda and scl 2 and 3 have to be inputs... right now you have them low and outputs..

portc = 0;
trisc = 0xff; <---- has to be inputs..
Sorry but I really detest MCC. It produces incomprehensible nonsense. I'd rather spend the time going through the datasheet and write my own. However, never used anything more powerful than an 18 series.

Mike.
Total agree here....
 

Latest threads

EE World Online Articles

Loading

 
Top