1

I'm trying to stream the data coming from my I2C MMA8452Q accelerometer to an Adafruit-based SSD1351 OLED RGB display that uses SPI via an Arduino UNO.

When I run example code for the accelerometer I can see it outputting data to the serial monitor, and when I run my code for the screen using a joystick as test input it graphs the values nicely.

When I try and build in the I2C example code into my code for the display, the moment I include to the code to read the values from the accelerometer, the program runs setup and then goes blank after that. When I block out the sensor read and swap in the joystick reads it works fine again.

I've been staring at all kinds of forum posts about using SPI and I2C simultaneously but I haven't really found any with a straightforward solution or they use a very different board.

#include <Adafruit_SSD1351.h>
#include <SparkFun_MMA8452Q.h>
#include <SPI.h>
#include <Wire.h>

#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 128 // Change this to 96 for 1.27" OLED.

// You can use any (4 or) 5 pins 
#define SCLK_PIN 2  // not using this as I've got it setup 
#define MOSI_PIN 3  // on the hardware SPI pins as per the text below
#define DC_PIN   4
#define CS_PIN   5
#define RST_PIN  6  // not in use

#define joy_XPin A1
#define joy_YPin A0

// Color definitions
#define BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

// Option 1: use any pins but a little slower
// Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, CS_PIN, DC_PIN, MOSI_PIN, SCLK_PIN, RST_PIN);  

// Option 2: must use the hardware SPI pins 
// (for UNO thats sclk = 13 and sid(which is SDA on my display) = 11) and pin 10 must be 
// an output. This is much faster - also required if you want
// to use the microSD card (see the image drawing example)
Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, CS_PIN, DC_PIN, RST_PIN);


MMA8452Q accel; // intialise sensor - SDA/SCL connected to A4/A5 pins as per example code


#define graphLength 32

int joy_X, joy_Y;
int tilt_X, tilt_Y;

int graphY[graphLength] = {0};
int graphX[graphLength] = {0};


void setup() {
  Serial.begin(9600);
  tft.begin();
  Wire.begin();

 
  tft.fillScreen(BLACK);
  
  tft.setCursor(10,64);
  tft.setTextColor(WHITE);
  tft.println("Welcome, have fun");

  delay(2000);
  tft.fillScreen(BLACK);
}

void loop() {

  // scaled inputs to be smaller and offset to be in the middle of the screen
  joy_X = (analogRead(joy_XPin) / 32)+48; 
  joy_Y = (analogRead(joy_YPin) / 32)+48;

  // when this block is included everything breaks
  // this is the code to read the accelerometer input so I'm pretty sure the issue is here.
  /*
  if(accel.available()){
    tilt_X = accel.getCalculatedX() * 10;
    tilt_Y = accel.getCalculatedY()* 10;
  }
  */

  graphY[graphLength - 1] = tilt_X; // swap tilt_X/Y with joy_X/Y to graph joystick inputs
  graphX[graphLength - 1] = tilt_Y;
  for(int i = 0; i <= (graphLength - 1); i++){  // invokes undefined behaviour but it works for now
    tft.drawPixel(i,graphY[i],RED); 
    tft.drawPixel(i,graphX[i],BLUE);
  }

  
  delay(5);
  graphShiftAlong();
}



// Just functions to clear the things I've drawn on the display rather than trying to wipe the whole display each time.


void clearPixel(uint16_t x, uint16_t y){
  tft.drawPixel(x, y, BLACK);
}

void drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color){
  int x1,y1,x2,y2;
  w = w/2;
  h = h/2;
  
  x1 = x - w;
  y1 = y - h;
  x2 = x + w;
  y2 = y + h;
  
  tft.drawLine(x1,y1,x1,y2,color); // top left to bottom left
  tft.drawLine(x1,y1,x2,y1,color); // top left to top right
  tft.drawLine(x2,y1,x2,y2,color); // top right to bottom right
  tft.drawLine(x2,y2,x1,y2,color); // bottom right to bottom left
}

void clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h){
  drawRect(x,y,w,h,BLACK);
}

// Sets the 'old' data to be drawn as black and redraws it one pixel offset
// Compiler gives me red text but not errors so I'm running with it for now
void graphShiftAlong(){
  for(int i = 0; i <= (graphLength - 1); i++){
    tft.drawPixel(i,graphY[i],BLACK);
    tft.drawPixel(i,graphX[i],BLACK);
    graphX[i] = graphX[i+1];
    graphY[i] = graphY[i+1];
  }
}

The example code I'm using for the sensor is here:

  Library for the MMA8452Q
  By: Jim Lindblom and Andrea DeVore
  SparkFun Electronics

  Do you like this library? Help support SparkFun. Buy a board!
  https://www.sparkfun.com/products/14587

  This sketch uses the SparkFun_MMA8452Q library to initialize
  the accelerometer and stream calcuated x, y, z, acceleration
  values from it (in g units).

  Hardware hookup:
  Arduino --------------- MMA8452Q Breakout
    3.3V  ---------------     3.3V
    GND   ---------------     GND
  SDA (A4) --\/330 Ohm\/--    SDA
  SCL (A5) --\/330 Ohm\/--    SCL

  The MMA8452Q is a 3.3V max sensor, so you'll need to do some
  level-shifting between the Arduino and the breakout. Series
  resistors on the SDA and SCL lines should do the trick.

  License: This code is public domain, but if you see me
  (or any other SparkFun employee) at the local, and you've
  found our code helpful, please buy us a round (Beerware
  license).

  Distributed as is; no warrenty given.
*/

#include <Wire.h>                 // Must include Wire library for I2C
#include "SparkFun_MMA8452Q.h"    // Click here to get the library: http://librarymanager/All#SparkFun_MMA8452Q

MMA8452Q accel;                   // create instance of the MMA8452 class

void setup() {
  Serial.begin(9600);
  Serial.println("MMA8452Q Basic Reading Code!");
  Wire.begin();

  if (accel.begin() == false) {
    Serial.println("Not Connected. Please check connections and read the hookup guide.");
    while (1);
  }
}

void loop() {
  if (accel.available()) {      // Wait for new data from accelerometer
    // Acceleration of x, y, and z directions in g units
    Serial.print(accel.getCalculatedX(), 3);
    Serial.print("\t");
    Serial.print(accel.getCalculatedY(), 3);
    Serial.print("\t");
    Serial.print(accel.getCalculatedZ(), 3);
    Serial.println();
  }
}

1 Answer 1

1

Your SPI is not setup for the Arduino UNO. Check another example for SPI and you will be using pins 11 and 13, this is mandatory and 8,9,10 or any three and there is a definition statement for these 3 pins - look at the example for your display. For I2C do you have pullup resistors on both I2C lines 4.7k up to 10k? These are required. Good luck

1
  • Sorry I should have clarified a bit more than what is in the code, I am using pins 11 and 13 for SPI, ignoring the setup defined early in the code. There are two declaration statements for the display - one uses any combination of pins for the display and the other uses 11 and 13 plus the other three. As for the pullup resistors, no I haven't put those in. However I did think that if the sensor worked when its own example code was run (even without the resistors) that it should run in conjunction with the display. Or is there some interference I am missing?
    – Tom W
    Jul 3, 2021 at 0:22

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.