CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

SSD1306 driver for use with less RAM
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 12947

View user's profile Send private message

PostPosted: Wed Feb 14, 2018 10:08 am     Reply with quote

As an update, I've just been running this with the SSD1309 (gives larger displays like 2.4"), and it runs fine. Only thing that gave problems was I found these needed a reset signal to stay low for a little while after power was applied to work reliably (ended up using a capacitor on the RES line), for reliable operation. Because this takes time, I had to pause for longer at boot. With this done works well. Smile
-Terppa-



Joined: 08 Jan 2018
Posts: 6
Location: Finland

View user's profile Send private message

PostPosted: Wed Mar 28, 2018 5:02 am     Reply with quote

Thank you very much for this driver Mr Ttelmah!
I have SSD1309 module which is modified on I2C- mode and it works great.
benoitstjean



Joined: 30 Oct 2007
Posts: 299
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Apr 03, 2018 7:15 pm     Reply with quote

Compiler: 5.026
Device: PIC18F14K50

Hi TTelmah,

I've successfully used your SSD1306 driver on an 128x64 display but I changed my display to a miniature one (0.49") 64x32.

The display initializes fine and I have just started to look through the pages but perhaps you may have some insight that will be faster than me trying to re-invent the wheel.

I appears that the address mapping is off because if I write the following:
Code:

   size = NORMAL;

   OLED_gotoxy( 0, 0 );
   OLED_text( "ABCDEFGHIJKLMNOP", 26 );

   OLED_gotoxy( 0, 1 );
   OLED_text( "zyxwvutsrqponmlk", 26 );

   OLED_gotoxy( 0, 2 );
   OLED_text( "abcdefghijklmnop", 26 );

   OLED_gotoxy( 0, 3 );
   OLED_text( "ZYXWVUTSRQPONMLK", 26 );

All 4 lines contain text. But the problem is that the first character of each line is cut in half and starts at the 6th character.

So:
First line starts at half of letter 'F' and ends at letter 'P'.
Second starts at half of letter 'u' and ends at letter 'k'.
Third line starts at half of letter 'f'' and ends at letter 'p'.
Fourth line starts at half of letter 'U' and ends at letter 'K'.

When I say "starts at half", each character is 5 pixels wide but letter 'F', I don't see the first two columns.

I'll continue to read through your code and the datasheets but if you know off the top of your head, please let me know.

Thanks!

Benoit
Ttelmah



Joined: 11 Mar 2010
Posts: 12947

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 6:58 am     Reply with quote

The 64 column displays have the starting value offset.
If you look at the github library here:
<https://github.com/WaiakeaRobotics/Adafruit_SSD1306/blob/master/Adafruit_SSD1306.cpp>
They offset by 0x20, and by 3 on the page address values. You'll need to do the same.
benoitstjean



Joined: 30 Oct 2007
Posts: 299
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 7:26 am     Reply with quote

That's what I thought it was by looking closer at the specs this morning. Ok, I'll give it a try tonight.

Thanks a million! You rock!

Benoit
benoitstjean



Joined: 30 Oct 2007
Posts: 299
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 9:00 pm     Reply with quote

So I tried the offset and still no success.

I looked at the code you suggested and I don't see in that code where the "void Adafruit_SSD1306::display(void)" function is used and that's where the S_COLUMNADDR and S_PAGEADDR are used. I compared my initialization sequence below with the one you referred to and they are the same except for S_COLUMNADDR and S_PAGEADDR which I added after S_MEMORYMODE and still that doesn't have any effect.

I took your ROM BYTE init_sequence[] structure and added / modified the missing commands (S_COLUMNADDR and S_PAGEADDR):

Code:

ROM BYTE init_sequence[] = S_DISPLAYOFF,           // 0xAE - Turn off oled panel
                           
                           S_SETDISPLAYCLOCKDIV,   // 0xD5 - Set display clock divide ratio/oscillator frequency
                           0x80,                                //      - Set divide ratio
                           
                           S_SETMULTIPLEX,              // 0xA8 - Set multiplex ratio(1 to 64)
                           0x1F,                                //      - 1/32 duty
                           
                           S_SETDISPLAYOFFSET,      // 0xD3 - Set display VERTICAL offset
                           0x00,                               //      - Not offset

                           S_SETSTARTLINE,              // 0x40 - Set start line address

                           S_CHARGEPUMP,               // 0x8D - Set Charge Pump enable/disable
                           0x14,

                           S_MEMORYMODE,              // 0x20 - Set memory adressing mode
                           0x00,

                           S_COLUMNADDR,               // 0x21 - Set column address
                           0x20,0x5F,  <-- Here, based on the calculations, it should be 0x20 + (64-1) = 0x5F since my OLED is a 64x32

                           S_PAGEADDR,                    // 0x22 - Set page address
                           0x00,0x03,

                           S_SEGREMAP | 0x01,            // 0xA1 - Set segment re-map
                           
                           S_COMSCANDEC,                   // 0xC8 - Set COM Output Scan Direction 64 to 0

                           S_SETCOMPINS,                    // 0xDA - Set com pins hardware configuration
                           0x12,

                           S_SETCONTRAST,                  // 0x81 - Set contrast control register
                           0xCF,                                    //        (0x4F is lower contrast)

                           S_SETPRECHARGE,                // 0xD9 - Set pre-charge period
                           0xF1,

                           S_SETVCOMDETECT,              // 0xDB - Set vcomh
                           0x40,                                   //      - Start line

                           S_DISPLAYALLON_RESUME,  // 0xA4 - Resume Entire Display On
                           
                           S_NORMALDISPLAY,             // 0xA6 - Set normal display
                           
                           S_DISPLAYON;                    // 0xAF - Turn on oled panel


As it stands now, I am trying to print the following:

Code:

   OLED_gotoxy( 0, 0 );
   OLED_text( "ABCDE98765", 10 );
   OLED_gotoxy( 0, 2 );
   OLED_text( "abcde01234", 10 );


The screen seems to be split in half with the right half being just random pixels on and off. The left half contains two lines. Each line is cut in half at #9 on the first line and #0 on the second line.

For the life of me, this should be quite simple. It's just a bunch of commands.

Any ideas are welcome.

Thanks again,

Ben
benoitstjean



Joined: 30 Oct 2007
Posts: 299
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Apr 05, 2018 5:06 pm     Reply with quote

Got it! Yes!!

So two things need to be done to the driver in order for the 64x32 OLED (0.49") displays to work:

1) Modify the initialization function to the following:

Code:


ROM BYTE init_sequence[] = S_DISPLAYOFF,           // 0xAE - Turn off oled panel
                           
                           S_SETDISPLAYCLOCKDIV,   // 0xD5 - Set display clock divide ratio/oscillator frequency
                           0x80,                   //      - Set divide ratio
                           
                           S_SETMULTIPLEX,         // 0xA8 - Set multiplex ratio(1 to 64)
                           0x1F,                   //      - 1/32 duty
                           
                           S_SETDISPLAYOFFSET,     // 0xD3 - Set display VERTICAL offset
                           0x00,                   //      - Not offset

                           S_SETSTARTLINE,         // 0x40 - Set start line address

                           S_CHARGEPUMP,           // 0x8D - Set Charge Pump enable/disable
                           0x14,

                           S_MEMORYMODE,           // 0x20 - Set memory adressing mode
                           0x00,

                           S_SEGREMAP | 0x01,      // 0xA1 - Set segment re-map
                           
                           S_COMSCANDEC,           // 0xC8 - Set COM Output Scan Direction 64 to 0

                           S_SETCOMPINS,           // 0xDA - Set com pins hardware configuration
                           0x12,

                           S_SETCONTRAST,          // 0x81 - Set contrast control register
                           0xCF,                   //        (0x4F is lower contrast)

                           S_SETPRECHARGE,         // 0xD9 - Set pre-charge period
                           0xF1,

                           S_SETVCOMDETECT,        // 0xDB - Set vcomh
                           0x40,                   //      - Start line

                           S_DISPLAYALLON_RESUME,  // 0xA4 - Resume Entire Display On
                           
                           S_NORMALDISPLAY,        // 0xA6 - Set normal display
                           
                           S_DISPLAYON;            // 0xAF - Turn on oled panel



2) In this function, add the 4-line snippet indicated below:

Code:

void OLED_address(unsigned int8 x, unsigned int8 y)
{
   //routine to move the memory pointers to x,y.
   //x is 0 to 127 (column), y (row) is 0 to 7 (page only)
#ifdef SH1106
   x+=2;
#endif
   i2c_start();
   i2c_write (SSDADDR); //select the display   
   i2c_write(COMMAND_ONLY); //we are sending command(s)

   //-------------- ADD FROM HERE --------------
   #define OLED_64x32
   #ifdef OLED_64x32
   x+= 0x20; // Add 0x20 offset
   #endif
   //------------------- TO HERE ------------------

   i2c_write(S_ROWADDRESS | y); // 0xB0 - select the display row
   i2c_write(S_SETLOWCOLUMN | ( x  & 0x0F )); // 0x00 - low col address
   i2c_write(S_SETHIGHCOLUMN | (( x >> 4 ) & 0x0F)); // 0x10 - high col address
   
   i2c_stop();
} //also made more efficient



So this works on the 0.49" OLED displays found on Ebay like this one:
<https://www.ebay.ca/itm/Blue-0-49-inch-OLED-Display-Module-128-32-0-49-I2C-IIC-for-Arduino-Best-glf/152750867470?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649>

Note that when I say "works", I mean that displaying the following code lines works fine:

Code:

   OLED_commands( init_sequence, sizeof( init_sequence ));                       // Initialise OLED display

   set = TRUE;                                                                   // Set background to black
   size = NORMAL;

   OLED_CLS();

   OLED_gotoxy( 0, 0 );
   OLED_text( "ABCDE98765", 10 );
   OLED_gotoxy( 0, 1 );
   OLED_text( "abcde01234", 10 );

   OLED_gotoxy( 0, 2 );
   OLED_text( "abcdefghiJ", 10 );
   OLED_gotoxy( 0, 3 );
   OLED_text( "ZYXWVUTSRQ", 10 );

   while( 1 );


Prior to that, the lines would start to get displayed at the half of the 5th character then garbage was on the screen. Now everything is properly aligned.

Thanks!

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 12947

View user's profile Send private message

PostPosted: Sat Apr 14, 2018 11:14 pm     Reply with quote

Well done,
Sorry I wasn't able to help much. I've been away.
adrianleal



Joined: 16 May 2018
Posts: 1

View user's profile Send private message

AdrianLeal
PostPosted: Wed May 16, 2018 3:37 pm     Reply with quote

Ttelmah wrote:
I do a large logo on one of my units.

I just have it declared in ROM as:
Code:

ROM BYTE const Plogo[] =
{
//With 512 bytes of data here.
};

//Then send it with:
//Move a line from the ROM array into RAM
void get_line(ROM BYTE *array, BYTE * target)
{
   int16 ctr;
   for (ctr=0;ctr<64;ctr++)
      *(target++) = array[ctr*8];
}

void draw_logo(void)
{
   BYTE line[64];
   signed int16 y;
   //routine to write the logo
   //Logo is in a 512 byte array, designed to occupy the second half of the screen
   //each row on the screen is every eighth byte along the array
   set=TRUE;
   size=NORMAL;
   OLED_cls();
   for (y=7;y>=0;y--)
   {
      OLED_address(62,7-y); //position the display
      get_line(&logo[y],line); //64 bytes
      OLED_data(line,64);
   }



The key is the use of OLED_address then OLED_data to send a line of data.

It's a decision you would have to make as to whether you should write a version accepting constant data or (as I do), just buffer the lines.

This occupies the right hand half of the screen.

Have fun. Smile



Hello
the code works perfect Thank you very much
I am occupying it with PIC18F4550 at 48Mhz. with USB connection with frimware load by Bootloader.

I wanted to incorporate characters like the Bluetooth symbol; Logo and others. But here I can not do it.

You could publish or send me a more explicit code. I'm not very good at this.

Thank you so much Confused Confused
_________________
AdrianLeal
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group