1

As a hands-on guy, I've started my first ever Arduino project 5 hours ago with no prior knowledge about Arduinos (I have coding experience tho. included this in case I am missing something obvious to the veterans around here). So far I have been able to hook-up 3 SSD1306 SPI OLED displays to my Uno, and created a script that allows me to control each display separately. Because my goal is to have 5 displays work off one Arduino, I figured to pin everything over to my Mega since it has more outputs (not sure yet about the differences between DIGITAL PWM on the Uno, and the 53 additional DIGITAL pins on the Mega).

First problem I encountered is that I couldn't find where the clock pulse was specified in the demo script. It's pinned on the Uno on pin 13, but this is not specified somewhere in that script, and I think once I understand the differences in pins from both boards, I might be able to help myself a few more steps into the future.

So to sum up my questions.

  1. How or where is the ClockPulse being specified.
  2. Can I use the 53 DIGITAL pins on the Mega, instead of the 13 DIGITAL PMW that I have on my Uno, and if yes, do I need to change some settings?

Here is my current script that works on my Uno, but not on my Mega, even if I use the same DIGITAL PMW pins on my Mega.

#include "HCuOLED.h"
#include "SPI.h"

//#define CS_DI 10
//#define DC_DI 9
//#define RST_DI 8

//HCuOLED HCuOLED_1(SSD1307, CS_DI, DC_DI, RST_DI); // For SSD1307 displays (HCMODU0050 & HCMODU0052)
HCuOLED HCuOLED_1(SSD1307, 10, 9, 8); // For SSD1307 displays (HCMODU0050 & HCMODU0052)
HCuOLED HCuOLED_2(SSD1307, 7, 6, 5); // For SSD1307 displays (HCMODU0050 & HCMODU0052)
HCuOLED HCuOLED_3(SSD1307, 4, 3, 2); // For SSD1307 displays (HCMODU0050 & HCMODU0052)


void setup()
{
  HCuOLED_1.Reset();
  HCuOLED_2.Reset();
  HCuOLED_3.Reset();
}

void loop()
{
  //display 1
  HCuOLED_1.SetFont(Terminal_8pt);
  HCuOLED_1.Cursor(44,0);
  HCuOLED_1.Print("Cpt");
  HCuOLED_1.Cursor(20,10);
  HCuOLED_1.Print("Fastlane");

  HCuOLED_1.Cursor(14,24);
  HCuOLED_1.SetFont(LCDLarge_24pt);
  HCuOLED_1.Print("KM/H");
  HCuOLED_1.Refresh();

  HCuOLED_1.ClearBuffer();

  //display 2
  HCuOLED_2.SetFont(Terminal_8pt);
  HCuOLED_2.Cursor(44,0);
  HCuOLED_2.Print("Cpt");
  HCuOLED_2.Cursor(20,10);
  HCuOLED_2.Print("Fastlane");

  HCuOLED_2.Cursor(14,24);
  HCuOLED_2.SetFont(LCDLarge_24pt);
  HCuOLED_2.Print("RPM");
  HCuOLED_2.Refresh();

  HCuOLED_2.ClearBuffer();

  //display 3
  HCuOLED_3.SetFont(Terminal_8pt);
  HCuOLED_3.Cursor(44,0);
  HCuOLED_3.Print("Cpt");
  HCuOLED_3.Cursor(20,10);
  HCuOLED_3.Print("Fastlane");

  HCuOLED_3.Cursor(14,24);
  HCuOLED_3.SetFont(LCDLarge_24pt);
  HCuOLED_3.Print("Info");
  HCuOLED_3.Refresh();

  HCuOLED_3.ClearBuffer();
}

And here is the original script:

#include "HCuOLED.h"
#include "SPI.h"

/* Example bitmap */
const PROGMEM byte Tiny_Logo_Resistor[] =
{
  0xC0, 0xE0, 0x30, 0x30, 0xF0, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0x38, 0x0E, 0x07, 0x1E, 0x78, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x70, 0x1C, 0x07, 0x0F, 0x3C, 0xF0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF0, 0x3C, 0x0F, 0x07, 0x1C, 0x70, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0x78, 0x1E, 0x07, 0x0E, 0x38, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xF0, 0x30, 0x30, 0xE0, 0xC0,
  0x00, 0x01, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x3C, 0x38, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x1E, 0x38, 0x1C, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x38, 0x38, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x1C, 0x38, 0x1E, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x38, 0x3C, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x01, 0x00,
};


/* Digital pin number for the displays chip select pin */
#define CS_DI 10
/* Digital pin number for the displays data/command pin */
#define DC_DI 9
/* Digital pin number for the displays reset pin */
#define RST_DI 8

/* Array indexes for the X and Y coordinates */
#define X1 0
#define Y1 1
#define X2 2
#define Y2 3

/* Arrays to store coordinates and direction for the line, rectangle and bitmap */
byte Box[4] = {1,1,20,20};
byte BoxDir[4] = {1,1,1,1};
byte Line[4] = {100,25,120,55};
byte LineDir[4] = {-1,-1,-1,-1};
byte Bitmap[2] = {40,40};
byte BitmapDir[2] = {-1,-1};



/* Create an instance of the library (uncomment one of the lines below) */
//HCuOLED HCuOLED(SSD1307, SS_DI, DC_DI, RST_DI); // For SSD1307 displays (HCMODU0050 & HCMODU0052)
HCuOLED HCuOLED(SH1106, CS_DI, DC_DI, RST_DI); // For SH1106 displays (HCMODU0058 & HCMODU0059)


void setup()
{

  /* Reset the display */
  HCuOLED.Reset();
}

void loop()
{
  /* Display some text using a small 8x8 fixed width font */
  HCuOLED.SetFont(Terminal_8pt);
  HCuOLED.Cursor(44,0);
  HCuOLED.Print("HOBBY");
  HCuOLED.Cursor(20,10);
  HCuOLED.Print("COMPONENTS");

  /* Display a number using a large 4 line LCD style font */
  HCuOLED.Cursor(20,24);
  HCuOLED.SetFont(LCDLarge_24pt);
  HCuOLED.Print("HCuOLED");

  /* Change the draw mode from NORMAL to INVERT */
  HCuOLED.DrawMode(INVERT);
  while(1)
  {
    /* Move the positions of the 3 objects */
    MoveRect();
    MoveLine();
    MoveBitmap();

    /* Draw the objects to the display buffer */
    HCuOLED.Rect(Box[X1],Box[Y1],Box[X2],Box[Y2], SOLID);
    HCuOLED.Line(Line[X1],Line[Y1],Line[X2],Line[Y2]);

    HCuOLED.Cursor(Bitmap[X1],Bitmap[Y1]);
    HCuOLED.Bitmap(84, 2, Tiny_Logo_Resistor);

    /* Write the display buffer to the screen */
    HCuOLED.Refresh();

    /* Draw the objects again. As we are in INVERT mode this will remove them */
    HCuOLED.Rect(Box[X1],Box[Y1],Box[X2],Box[Y2], SOLID);
    HCuOLED.Line(Line[X1],Line[Y1],Line[X2],Line[Y2]);

    HCuOLED.Cursor(Bitmap[X1],Bitmap[Y1]);
    HCuOLED.Bitmap(84, 2, Tiny_Logo_Resistor);
  }
}


/* Update the X and Y coordinates for the box */
void MoveRect(void)
{
  if(Box[X1] == 0 || Box[X1] == 127)
    BoxDir[X1] *= -1;
  Box[X1] += BoxDir[X1];

  if(Box[Y1] == 0 || Box[Y1] == 63)
    BoxDir[Y1] *= -1;
  Box[Y1] += BoxDir[Y1];

  if(Box[X2] == 0 || Box[X2] == 127)
    BoxDir[X2] *= -1;
  Box[X2] += BoxDir[X2];

  if(Box[Y2] == 0 || Box[Y2] == 63)
    BoxDir[Y2] *= -1;
  Box[Y2] += BoxDir[Y2];   
}

/* Update the X and Y coordinates for the Line */
void MoveLine(void)
{
  if(Line[X1] == 0 || Line[X1] == 127)
    LineDir[X1] *= -1;
  Line[X1] += LineDir[X1];

  if(Line[Y1] == 0 || Line[Y1] == 63)
    LineDir[Y1] *= -1;
  Line[Y1] += LineDir[Y1];

  if(Line[X2] == 0 || Line[X2] == 127)
    LineDir[X2] *= -1;
  Line[X2] += LineDir[X2];

  if(Line[Y2] == 0 || Line[Y2] == 63)
    LineDir[Y2] *= -1;
  Line[Y2] += LineDir[Y2];   
}

/* Update the X and Y coordinates for the bitmap */
void MoveBitmap(void)
{
  if(Bitmap[X1] == 0 || Bitmap[X1] == 43)
    BitmapDir[X1] *= -1;
  Bitmap[X1] += BitmapDir[X1];

  if(Bitmap[Y1] == 0 || Bitmap[Y1] == 47)
    BitmapDir[Y1] *= -1;
  Bitmap[Y1] += BitmapDir[Y1];
}

1 Answer 1

2

You are communicating with your OLED displays using SPI - Serial Peripheral Interface. This is a special hardware peripheral built in to the MCU, and the outputs of it are physically connected inside the MCU to what become pins 11-13 on the Arduino UNO.

This, and other things like the UART, PWM and the analog inputs, are known as alternate functions of the pins.

On small MCUs like the Arduino uses these functions are fixed in hardware (more advanced MCUs employ a system to allow you to map the functions to different pins).

When you use SPI on the UNO it always uses pins 11-13 (MOSI, MISO and SCK in that order). When you use SPI on the Mega it always uses pins 51, 50 and 52 (in that order for the same functions). You can't change it. Pin 10 on the UNO is the Slave Select pin, and that again is an alternate function which is hard wired. On the mega that function is pin 53.

For SPI to work as a master (which is what you want) then pin 10 on the UNO or pin 53 on the Mega must be set to OUTPUT. It doesn't matter if you actually use it, but it has to be set to OUTPUT as that defines the direction the SPI peripheral operates in.

So for the Mega you would wire your OLED displays to pins 51, 50 and 52 instead of pins 11, 12 and 13. You could use pin 53 as one of your chip select pins (though you don't have to, just as long as you set it to OUTPUT).

Incidentally, you can save pins on your setup by sharing some of them. The only pin that need to be unique for each OLED is the Chip Select pin. That is the pin that tells the OLED that it is being spoken to. Only when that pin is active will the OLED listen to any of the other pins.

The only other one you may need to connect separately is the reset pins, since you reset the displays in turn - resetting the second would reset the first and undo the configuration. TBH I'd connect the RESET pins of the OLEDs to a single pin, and specify another (unused, or non-existent) pin in the constructors for RESET - then manually reset all the OLEDs together through the one LOW pulse of the RESET pin, and then call the reset functions for each display, which should configure them all.

That way you are then using just (example UNO pins numbers shown):

  • MOSI (11)
  • MISO (12)
  • SCK (13)
  • DC (7)
  • RESET (6)
  • CS1 (10)
  • CS2 (9)
  • CS3 (8)
16
  • Amazing stuff! Ill probably have to read it a couple of times before I can fully wrap my head around it. I dont fully understand the RESET part, because the way I see it, it seems that I cannot get arround having to use one pin on the board per display, be it via the regular way, or manually. Could you elaborate? By sharing the DC pins I do free up 3 more pins that allows me to add 2 screens, and have one more pin that will eventually control my rev bar (havent figured that bit out yet, but it will be a bar of LEDs that will take in RPM data).
    – sdieters
    Commented Aug 11, 2018 at 19:57
  • Also, when i've connected pin 50 and 52 (not using pin 10 on the UNO now), can I assign DC, RESET and CS to any of the other 49 digital pins on the MEGA? (post became to long)
    – sdieters
    Commented Aug 11, 2018 at 19:57
  • Yep, DC, CS and RESET can be any pin you like (even Analog pins). When you share pins (like DC) all the displays get sent the DC setting (HIGH or LOW), but only one does anything with it - the display that currently has the CS pin LOW.
    – Majenko
    Commented Aug 11, 2018 at 20:18
  • Ohh i see now (I think haha). So I can combine all pins except CS, and instead of doing the regular .display () command, I first manually set the output for whatever pin is CS for the display I wanna update to LOW, and then use the .display() function (after updating the data to display that is)?
    – sdieters
    Commented Aug 11, 2018 at 21:12
  • The library is doing that for you. Just repeat the same numbers in the constructors.
    – Majenko
    Commented Aug 11, 2018 at 21:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.