SSD1306 LCD and updates!

Well! Its been a long time since I’ve actually blogged as I’ve been so busy! I’m now back at university (with 25 hours of contact time/week), along with vice president’ing UoN ShockSoc (https://twitter.com/Shock_Soc) and being the general secretary of BladeSoc (https://twitter.com/UoNBladeSoc), leaves little time for me to do much else! I have however been asked my one of my readers to do a quick update on the SSD1306 LCD library so here I am!

I wrote the original library a fair bit of time ago so the quality of coding isn’t amazing but hopefully it should be good enough to give people a gist of whats happening. As with everything, the LCD I’m using a is a cheapo 128×64 OLED that can be bought off eBay (http://goo.gl/0Pkvyn – Link will expire!) for ~Ā£3. OLED Displays are so cool in the sense that they can provide crisp and even backlit images as each pixel is essentially an organic LED. This has the downside of increased current compared to conventional LCD’s but with the advantages of crisper more defined images, as an example, the Samsung range of high end phones use AMOLED displays which are designed around the whole OLED idea, giving some of the best colour representation available on phones today!

None the less, onwards with the library!

P1020536
The LCD with my trusty STM32F0 Discovery board.

The whole sketch to test the LCD can be found on my Github. I’ve left the pin wiring as comments in the Github file! šŸ™‚

Further on with news:
As the vice president of ShockSoc, it is up to me to choose the year long engineering project for the society! With some deep thought, I’ve decided to design an electric trike! For those who have read my about page, it is going to be quite like the one I’ve previously designed (hence, I feel its a pretty safe project for me to be able to complete by the end of the year) except there will be no welding, it will hopefully be a lot safer and will look much more professional! With the help of one of my fellow engineering friends, we’ve done some preliminary mechanical calculations to ensure the frame will be able to bear the mass of a large student, and still function correctly.

My friend is a mechanical engineer so he is quite advances in using Creo, something I’m not advanced in… at all. Regardless, the other night, we got our planning heads together and have sketched up the preliminary cad diagram:

TrikeModel
The beginnings of the ShockSoc trike!

Due to the university policy, I’m not allowed to purchase parts off eBay which increases the budget by a fair amount but I think we should still be able to do it relatively cheaply. The main expense comes from the hub motor (at the front), controller and steel frame work. Fortunately, most of the parts are available from renowned sources such as The Metal Store (http://www.themetalstore.co.uk/) and I will likely be buying the hub motor from Amazon.

Keep tuned for more ShockSoc updates!

Advertisements

30 responses to “SSD1306 LCD and updates!

    • Hi Tim!
      One way you could rotate the screen is by modifying how the data is sent from microcontroller to screen by reversing the PScrn() function. Instead of starting at 0 and going up to GBufS, start at GBufS and go down to 0. That will write the data to the screen backwards.

      Another way that you can do it is through the initialization of the screen. If you go to page 31 of: https://www.adafruit.com/datasheets/SSD1306.pdf

      You can see that by modifying the value stored in the segment remap and COM direction registers, you can change how the data is written to the screen, by changing these registers, you should be able to write in nearly all orientations! šŸ™‚

      Hope that helps!

  1. It works now!
    One thing I’ve always wanted to ask you is: why is it that sometimes when I call the function PScr() (after I PStr() or PChar()), the text gets pixelated? Do I call the PScr() function once after I do all the PStr() and PChar() that I need, or I have to call it every time after a PStr() or PChar()? And when do I need to use the ClrBuf() function?

    • That doesn’t sound right! The text should definitely appear properly though having the text size as anything other than 0 might screw things up as I’ve not really completed writing the text scaling stuff.

      With regards to the functions:
      PStr – This prints a string of text into the graphics buffer
      PChar – This prints an individual character into the graphics buffer
      ClrBuf – This sets the WHOLE graphics buffer to black (essentially clearing the graphics buffer)
      PScrn – This sends the whole graphics buffer to the LCD byte at a time.

      So the way I generally do it is at the top of my program, clear the graphics buffer (ClrBuf), ready for me to write into the graphics buffer, I then do my writing using any of the functions (PStr, PChar, PNum, PNumF etc). Once I’ve finished writing into the graphics buffer, I push all of the data to the LCD using PScrn (which is a blocking function). By the time the program returns to the top, the data will have sent and should display on the LCD!

      Hope that helps šŸ™‚

      • Thank you for the fast reply Harris. Maybe I wasn’t clear on my question.
        The text displays correctly, but let’s say I write a line of characters (I used PChar() one after the other) on line 1 (y = 0) with font size of 0 (5×8). Then I go to the next line, starting at y = 10 or 11 (leave some space between the lines), and write another the line of characters. This would sometimes make the second line and even the first line’s text pixelated, like the text would be cut off a bit from the top and that cut off part would be move to the bottom of that line. Wish there was a way to add picture so you can understand what I meant. Do you think it’s a problem with the display? (I got the same one you have with the same pin layouts, but from a different vendor) Or is does it have something to do with the functions? Again, thank you so much. I really appreciate it

      • Hi Tim,
        That actually seems kinda weird, I don’t thin k I’ve ever had that problem. Could you tell me your exact function calls?

        To print strings across multiple lines (including clrbuf and pscrn calls), my work flow would look like:

        ClrBuf();
        PStr(“String 1”, 0, 0, 0, 0);
        PStr(“String 2”, 0, 8, 0, 0);
        PStr(“String 3”, 0, 16, 0, 0);
        PScrn();

        Obviously, you can do it in multiples of 8 instead of 10

        ClrBuf();
        PStr(“String 1”, 0, 0, 0, 0);
        PStr(“String 2”, 0, 10, 0, 0);
        PStr(“String 3”, 0, 20, 0, 0);
        PScrn();

        If you’ve changed the code to send the print buffer in reverse to the screen, this might be causing a bit of a problem but I don’t see why – I never tested that piece of code. Nonetheless, its probably best to actually do the screen rotation/flipping with the actual SSD1306 driver instead.

      • Hi Harris,
        This is what I have to test it:
        int col = 0;
        ClrBuf();
        PChar(‘E’,col,2,0,0);
        col+=6;
        //PScrn();
        PChar(‘C’,col,2,0,0);
        col+=6;
        //PScrn();
        PChar(‘E’,col,2,0,0);
        col+=6;
        //PScrn();
        PChar(‘4’,col,2,0,0);
        col+=6;
        //PScrn();
        PChar(‘4’,col,2,0,0);
        col+=6;
        //PScrn();
        PChar(‘8’,col,2,0,0);
        col+=6;
        PScrn();

        col = 0;
        PChar(‘A’,col,15,0,0);

        col+=6;
        PChar(‘B’,col,15,0,0);
        col+=6;
        PChar(‘C’,col,15,0,0);
        col+=6;
        PChar(‘D’,col,15,0,0);
        col+=6;
        PChar(‘E’,col,15,0,0);
        col+=6;
        PScrn();
        PChar(‘F’,col,15,0,0);
        col+=6;
        PChar(‘G’,col,15,0,0);
        col+=6;
        PChar(‘H’,col,15,0,0);
        col+=6;
        PChar(‘I’,col,15,0,0);
        col+=6;
        PChar(‘J’,col,15,0,0);
        col+=6;
        PChar(‘K’,col,15,0,0);

        I did’t change the PScrn() function at all. I just modified the Remap and ComScanDir as follows:
        //SB(SetRemap|1, 0, 1);// Original
        SB(0xA0,0,1); // added
        //SB(SetComScanDir|8, 0, 1);// Original
        SB(0xC0,0,1); // Added
        So that the screen is flipped 180 degrees. And even when I keep the original code, the problems is still there.

      • Some info to add (not sure if it will be useful): this only happens for font size of 0 (5×8). When i used 10×16 font size, it’s fine

  2. One more thing is your Delay() function. I don’t get how it works though. If you define it like that, wouldn’t we end up in an infinite loop (I already took out all your Delay() function calls)

    • No prob! Well the SysTick timer is an interrupt and increments a variable called MSec every millisecond EXTERNAL to the main program code. So regardless of what you put in the main code (unless you explicitly disable interrupts), the SysTick timer will produce a millisecond interrupt which increments the MSec variable. In the delay function, you’re grabbing the value of MSec at function entry, then in the while loop, comparing the current MSec-InitialMSec and waiting until its more than the specified delay time. It might seem that it would infinite loop – and it would if MSec wasn’t incremented in the interrupt, but fortunately, the interrupt allows MSec to increment while the Delay function is stuck in the while loop.

      Cheers!

      • Thanks again for the reply Harris. I didn’t see your SysTick(). I saw that you defined it in main.c, but maybe I missed something but I didn’t see where you call it

  3. I think the problem might be that I’m writing and deleting a lot of stuff from the screen. Let’s say when I press button A, It displays character A, then when I press Delete, it deletes A, then when I press X, it prints out a long string. Do you think that might be causing the problem? Maybe your buffer could not hold it all?

    • I’m not too sure at what the problem could be! All pixels should be overwritten when you write to them. Maybe try writing a ‘ ‘ (space) to the position you wish to write a character, then proceed to write the character over the space, that might work! The buffer doesn’t actually store operations done with the library, for example if you write more characters than the graphics buffer could ever hold, you will never get a memory overflow as the graphics buffers only actually stores what each individual pixel should be, not operations about writing to the display šŸ™‚ Hopefully that’ll help!

      • Thanks for the reply again Harris. I already tried your suggestion before and it did not help. The funny thing is, only font size of 0 (5×8) causes the problem. Font size of 1 (10×16) works just fine, but that would take way too much space on the screen and I would not be able to display as much stuff as I need to. Would it be possible for you to quickly take a look at my code to see what the problem might be?

      • Yeh I completely see your point! That’s really weird, I’d happily take a look at you code to see what the problem could be šŸ™‚

  4. it currently displays 4 lines of text representing 4 folders. To the right side is the cursor, and the cursor moves up and down when the up (key 2) and down (key 8) of the 4×4 keypad is pressed (you can easily swap them for any on-board buttons if you dont have a keypad handy, and just call the UI_navigate() function in UI.c). Moving the cursor up and down will gets the text pixelated. I’m not sure but does calling PScrn() multiple times mess it up?

    • Hi Tim,
      Ok, I’ve been looking through your code (I apologise if my assumptions are incorrect! I’m pretty bad at peer assessing code) but I’m assuming the application point of entry is the int main in app.c.

      I see your function “print_name” which I assume you’re trying to print your four strings, name, name0, name1 and name 2 to rows 1, 2, 3 and 4 respectively, so you’re printing the string with a spacing of 12 between the tops of each line right? (Nice shortcut with the RowNumber enum too!)

      So that all seems fine to me so far. In your print_name function, I assume this is your implementation of my PStr function. The thing I don’t understand however is: How come you’re printing an inverted size 2 decimal 2? The PChar function takes a unsigned short (16bit) and subtracts 32 from it (0x20) to allow the character to be used as an index for the character array. The problem comes with you sending a decimal 2 to this function. As the value is passed as uint16_t, it will underflow and rollover to ~65534 which then gets multiplied by 5, which will cause major overflowing ((~65534*5)%65535)! I’m actually pleasantly surprised that this hasn’t crashed the program as you’d be accessing memory space that isn’t what you’re supposed to be accessing (you’d be trying to access the base address of the chars array + 65531). If you could explain the PChar(2…), I’d probably be able to give a bit more advice on that section. Otherwise, printing the name array should be fine! PChar actually returns the next column where a character should be written (with space between characters defined by LetterSpace in GFX.h) so you could actually change from:

      PChar(name[i],x,y,0,0);
      //ssd1306DrawChar(x, y, name[i], Font_System5x8);
      //ClrBuf();
      i++;
      x+=6; // good at 8

      to

      x = PChar(name[i], x, y, 0, 0);
      i++;

      It’s good that you’ve commented out ClrBuf in the function because ClrBuf would just get rid of everything you’ve written to graphics buffer everytime the loop executes meaning once you exit the print name function, nothing would happen.

      So from entry up to the second print screen, I assume everything prints correctly? I can’t actually test it because I don’t have my display at home with me!

      Moving further down with the code:
      disp_square(Row_1)
      Above the while(1) loop won’t actually print to the screen ever as your while(1) doesn’t contain any calls for PScrn();

      For the commented out sections, I’m not too sure which parts you’ve tried and haven’t I’m afraid!

      • Thank you so much again for taking the time to help me. I wish there was a way for me to say thank you to you rather than just thanking you here, but thank you!

  5. Harris,
    I’m printing the inverted decimal 2 of size 2 to clear the space before I actually print out the character that I want to print out. Doing PChar(2,…) with pix inverted will clear whatever is on the screen at that position.
    And yes, everything prints out fine until I call the UI_navigate() function in UI.c and press either the up and down button (I have a keypad wired to it, and key 2 is moving up and key 8 is moving down), it would mess the text up

  6. Hi again Harris,
    It was a bad screen. I ordered a new one and all is fine now. Thanks again for your help and sorry if my questions bothered you.

  7. Hello Harris.
    I’m trying to use SSD1306 Display with STM32F4 Discovery via SPI. Are the wirings the same as STM32F0? I can’t seem to find the pin wirings on github as well. Any advice would be appreciated šŸ™‚

    • Hi Kyaw, the pinouts are in the SSD1306 header file! As far as I can recall, the pinout should be the same though if there are any onboard peripherals (I think there’s an audio DAC), its probably worth making sure they don’t share pins! Also, a couple of the APB/AHB peripheral enables will need to be changed as the stm32f4 has two AHB buses. Hope this helps!

      • Sorry to bother you again Harris. These are all new to me. I wanna use GPIOB on my STM32F4 and my pin wirings (in SSD1306.h) are:
        #define Clk GPIO_Pin_3
        #define DIn GPIO_Pin_5
        #define DC GPIO_Pin_4
        #define CE GPIO_Pin_0
        #define RS GPIO_Pin_7
        #define ClkPS GPIO_PinSource3
        #define DInPS GPIO_PinSource5
        #define IOGPIO GPIOB

        And in SSD1306_InitSetup() file (from SSD1306.c ), I enable
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

        However, GPIO_PinAFConfig(IOGPIO, ClkPS, GPIO_AF_0);
        GPIO_PinAFConfig(IOGPIO, DInPS, GPIO_AF_0);
        these two lines are giving me errors saying undeclared identifier ‘GPIO_AF_0’.
        In the file ‘stm32f4xx_gpio.c’, it says “GPIO_AF_SPI1: Connect SPI1 pins to AF5”. So, I’m guessing that I should change GPIO_AF_0 into GPIO_AF_SPI1.

        And for PNum (and PNumF) functions in GFX.c, there’s an error that says “conflicting types for PNum”

        Again, Thanks a lot and any help is appreciated.

  8. Hi Kyaw,

    OK so on the STM32F4 series of processors, you’ve correctly set up your GPIO clocks etc. so good job there! Looking at the datasheet though (http://goo.gl/nDkcqr), SPI1 is the 5th alternate function for PB3 and PB5, fortunately in the standard peripheral library all of the alternate functions are named so instead of GPIO_AF_0, you can use GPIO_AF_SPI1 (as you stated too!).

    I just looked back at the library and damn that is some poor coding! There is actually an error on my behalf with respect to the usage of PixT as a type, I seem to have changed it in the .c file and left it in the .h file. I’ll sort this out now and upload a hopefully successful build!

    Thanks,
    Harris

  9. Hi Kyaw,

    I’ve updated the graphics library and tested it out on my STM32F0, all should be good now! When using the STM32F4, make sure the SPI clock isn’t too fast, the LCD supports up to 10MHz.

    Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s