Is the problem in the code or in the OLED screen?

Hi Community!

I am trying to create a sort of a password generator device, where based on some input from the user (given by a rotary encoder for selecting the letters/digit + a switch for confirming the input of each letter/digit) the arduino will then return a password according to some calculations contained in the code.

The problem I am facing is that I was able to get the code to work by interacting with Arduino through serial monitor, as well as via LCD screen. However, if I try and run this code with my 128X64 OLED screen, it stops working and the Arduino simply appear to be stuck with the TX LED constantly going on and off.

Because the code works in every other case, I am starting to think that there is some interference caused by the way the screen works, however I am not really sure about this as I cannot logically explain how that could affect the result.

If anyone could give me a clue on how to solve this and finally make it work (I've been banging my head on this on and off for months now), I'll be forever grateful!



#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


char InputArray[100]; // stores the selected value from char Input
char Output[100]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
                             { 'g', 'h', 'i', 'j', 'k', 'l' },
                             { 'm', 'n', 'o', 'p', 'q', 'r' },
                             { 's', 't', 'u', 'v', 'w', 'x' },
                             { 'y', 'z', '0', '1', '2', '3' },
                             { '4', '5', '6', '7', '8', '9' } }; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

int num[2][100];  //first row to store reminder, second row to store quotients
int InputLen;
int i;
int Key = 2; // key to allow selection of the value to store in char InputArray
int fadeValue1; // raw potentiometer value
int fadeValue2; // potentiometer value adjusted to select one of the 36 options from char Input
char charselect; // to show and store selected value from char Input
int InputArrayPos = 0; //this is just for word positioning on the display
int cursor; // this is just for word positioning on the display
int CursorStart; // this is just for word positioning on the display
int CursorRef;  // this is just for word positioning on the display
int CursorEnd;  // this is just for word positioning on the display

void setup() {
  pinMode(Key, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextWrap(false);
  display.clearDisplay();
}

void loop() {

  fadeValue1 = analogRead(A0);
  fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  charselect = Input[fadeValue2];

  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");

  displayPrint(55, 15, WHITE, 4);
  display.println(charselect);

  if (fadeValue2 == 36) {
    displayPrint(18, 22, WHITE, 2);
    display.println("SHOW Output");
  }

  displayPrint(cursor, 47, WHITE, 2);
  display.println(InputArray);

  display.display();

  if ((digitalRead(Key) == 1) && (fadeValue2 != 36)) {

    InputArray[InputArrayPos] = charselect;
    InputArrayPos = InputArrayPos + 1;

    display.clearDisplay();
    displayPrint(0, 0, WHITE, 1);
    display.println("Your selection:");
    displayPrint(50, 22, WHITE, 2);
    display.println("OK!");

    InputLen = (strlen(InputArray));
    if (InputLen > 10) {
      cursor = (10 - InputLen) * 12;
    } else
      cursor = 0;

    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();

    delay(500);
  }


  while ((digitalRead(Key) == 1) && (fadeValue2 == 36)) {
    calculateOutput(); 
    displayOutput();
  }
}

void calculateOutput() {

  for (int i = 0; i < (InputLen - 1); i++) {
    num[0][i] = (InputArray[i] - 96) / 5;
    num[1][i] = (InputArray[i] - 96) % 5;
  }
 
 for (int i = 0; i < (InputLen - 1); i++) {
     Output[i] = AlphaNumChart[num[0][i]][num[1][InputLen - 1 - i]];
  }

}

void displayOutput() {

  CursorEnd = (-12 * InputLen) + display.width();
  CursorStart = 0;

  while (digitalRead(Key) == 1) {

    if (InputLen <= 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");

      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }

    if (InputLen > 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {CursorStart = CursorStart - 2; CursorRef = 0; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {CursorStart = CursorStart + 2; CursorRef = 1; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}

void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}

what's your arduino?
Any schema of the set up you could share?

I'm going to guess your code needs a 1k byte frame buffer, and runs out of RAM

I'm afraid I don't have a schema (wouldn't know how to create one unfortunately), the best I can do is upload this photo of the set-up. I hope this helps.

Thank you for your reply. Not sure if this is something that can be fixed, or is just a mission impossible for arduino? If so, I'd be surprised as I've seen them run pretty large and complex codes that seemed much more complicated than mine... :thinking:

Edit:
Perhaps I should also mention that when I compile the code, the Ardiuno IDE declares that the memory usage is within the limits

Use a pen and paper - usually the signal flows from left to right, power on top, ground on the bottom. Try to avoid crisscrossed lines and spaghetti. Label all the pins or connection points on every component that isn't a standard one, like a resistor. Attach values to any components that have one.

Regards the display, have you tried running the example sketches from the OLED library you're using?

does the example run with your exact breadboard setup?

what does the OLED definition look like in the example? does it match your code:

Yes it does, in fact the screen works fine even with this current code if only I remove the function that calls for CalculateOutput and DisplayOutput. Obviously the code would serve no purpose in that case as I am completely removing the part that calculates the result, but at least I can get the screen to work up until this point in the code, and I am able to visualize and interact with the program and select the word to input.

double check that you do not have out of bound array issues that could go uncaught in the Serial version and make a mess in the OLED version

➜ print the index you are using before assigning something into an array, for example here

 for (int i = 0; i < (InputLen - 1); i++) {
     Output[i] = AlphaNumChart[num[0][i]][num[1][InputLen - 1 - i]];
  }

can you guarantee InputLen-1 is fitting OK for your array (less than 100)

or in

    InputArray[InputArrayPos] = charselect;
    InputArrayPos = InputArrayPos + 1;

there is no check on InputArrayPos and it keeps growing (never reset)

Hi J-M-L, thank you for looking into this. I am sorry I don't think I understand the issue and how I am supposed to solve it, apologies for my if ignorance... If I understand correctly your second point, I guess that as long as the input word does not exceed 100 characters (the max size of the array), the fact that the InputArrayPos number keeps growing without resetting shouldn't constitute a problem, should it?

correct but if you reach 100 then you write beyond the bounds of the array. Can this happen?
I've not checked what the code does, just thinking aloud on what could lead to issues

➜ adding debug statements to print stuff would help

Hi J-M-L, reaching over 100 character is a scenario that would not happen. At any rate, this code is not working from the get-go, with the Arduino stuck in a reboot loop and not showing anything on the screen from the beginning, therefore not even allowing me to input anything that could potentially cause the array to grow beyond its capacity.

For the debug statement, this is actually the first time I hear about it. Is there any reference that you can share where I can find more on how I can do something like hat?

I assume your Arduino is connected to the PC using the USB connexion , just add Serial.print(...); Serial.flush(); statements in key locations where you play with the screen or arrays or where you suspect something weird might be happening.

for example instead of

    InputArray[InputArrayPos] = charselect;
    InputArrayPos = InputArrayPos + 1;

have

    Serial.print(F("InputArray: ")); Serial.println(  InputArrayPos); Serial.flush(); // DEBUG
    InputArray[InputArrayPos] = charselect;
    InputArrayPos = InputArrayPos + 1;

also when I see InputLen = (strlen(InputArray)); ➜ this only works if you have a cString, ie the array is null terminated. this is the case for global variables so you should be fine but ideally you would write a '\0' after the charselect (and check bounds)

1 Like
  fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  charselect = Input[fadeValue2];

first access beyond array. fadeValue2 can only be 0-35.

  display.println(InputArray);

Your InputArray is not a null terminated string. It is ONLY a null terminated string the very first time you run this code since it is a global variable and global variables are guaranteed to be filled with '\0'

void calculateOutput() {

  for (int i = 0; i < (InputLen - 1); i++) {
    num[0][i] = (InputArray[i] - 96) / 5;
    num[1][i] = (InputArray[i] - 96) % 5;
  }

  for (int i = 0; i < (InputLen - 1); i++) {
    Output[i] = AlphaNumChart[num[0][i]][num[1][InputLen - 1 - i]];
  }

}

Let's suppose InputArray[0] = '0'. What does this produce?
'0' = 48 and 48 - 96 = -48.
You then use it as an index into AlphaNumChart[]

1 Like

Hi blh64, thank you very much for your input. Could you help me understand why fadeValue2 can only be 0-35, when I remapped it to be 0-36 in the previous line?

About your second point, the code is actually able to run that command and always be displaying the inputArray (if I run the code without the password calculation part). In any case, I understand that perhaps this is something that should be fixed regardless, do you have suggestion on how I can terminate the string after each character/digit that I add to the input?

Regarding your last point, that's a good call, I didn't realize until now. I guess I can try and fix that by assigning some arbitrary values to those digit that do not correspond to the actual ASCII code, but that would allow me to run the calculation.

Thank you very much, I'll try as soon as I have a chance and report back on the result!

For the boundaries in InputArray, another comment also mentioned the same thing so it looks like this is definitely something I need to fix. Any suggestion on how I can make sure that the array is terminated after each character/digit that is added to the array?

By putting a terminator after each character as it is entered.

InputArray[InputArrayPos++] = charselect;
InputArray[InputArrayPos] = '\0';

(Of course, you've already ensured there's space for both...)

It should only be 0-35 since your array has 36 elements and you can access them with 0..35. Accessing with an index of 36 gives you the non-existant 37th element.

As for the string always being terminated, just terminate after every new addition

InputArray[InputArrayPos++] = charselect;
InputArray[InputArrayPos] = '\0';

And you really should put in same checking to keep is inside your buffer size.

I see what you mean now about the 37th element. That actually exists, although you won't find it in the array but in this if statement

  if ((digitalRead(Key) == 1) && (fadeValue2 != 36))

It serves the purpose of telling the code to start calculating the password.

And thank you very much for the advice, I wonder if by fixing the inputArray boundaries by terminating it and by changing the value of the digits 0-9 will finally allow the code to run. Will definitely fix those two things and report back!

No, it does not exist. The code is reaching beyond the end of the array. Accessing it that way is undefined behavior and all bets are off. Practically speaking, you are just reading some garbage/other variable that happens to occupy that space. On a different architecture, the OS could detect that and terminate or whatever