Hello! I have come across a strange finding using an OLED display and Current sensor that both uses SPI.
The issue is that only one or the other works at a time.
To get the current sensor working I have to move the u8g2.begin call for the OLED in front of the SPI.begin.
To get the OLED display working I have to move the u8g2.begin call after the SPI.begin.
This is my code so far:
#include <Arduino.h>
#include <EEPROM.h>
#include <TimeLib.h>
#include <Servo.h>
#include <Streaming.h>
#include <SPI.h>
#include <Wire.h>
#include "HX711.h"
#include <Adafruit_MAX31856.h>
#include <Adafruit_Sensor.h>
#include <U8g2lib.h>
#include <ezButton.h>
/*--------------------- INPUTS ------ to receive signals ---------------*/
/*--------------------- SPI ---------------------
pins 11 12 13 are dedicated SPI pins. All SPI devices
will be connected to these pins. The only extra pins
needed for the SPI devices are the Chip Select pin.
See the OUTPUTS declaration section of what CS pins
are being used.
*/
/*START BUTTON*/
#define STARTER_BUTTON_ON_OFF 30
#define NAVI_BUTTON 34
#define SELECT_BUTTON 35
#define HEATER_ON_OFF 5
/*NOTE: POWER SENSOR*/
/* ^^^ POWER SENSORS are input */
#define CS_CHARGE_V_I_SENSOR 4 //charge enable selection for BB2557/U
#define CS_OUTPUT_V_I_SENSOR 10 //v/i sensor for output
#define CS_DISPLAY 20 //selection for display
#define CS_ENG_TEMP_PIN 39 //seletion for eng temp
#define CS_HEATER_TEMP_PIN 40 //selection for heater temp
/*TEMP MAX31856 FAULT PINS*/
#define FAULT_ENGINE 25
#define FAULT_HEATER 28
/*DISPLAY PINS*/
#define RES_DISPLAY 26
#define DC_DISPLAY 27
/*DISPLAY*/
int flagA = 0; // flag for the first state of the display
int flagB = 1; // flag for the second state of the display
struct {
int power = 0;
int operationalHours = 0;
int voltage = 0;
int fuel = 0;
int insideBattery = 0;
char myPower[6];
char totalHours[6];
char outputVoltage[6];
char myFuel[6];
char intBattery[6];
} mDisplay;
elapsedMillis taskTimer; // elapsed timer from PJR teensy
unsigned int displayTimer = 1000; // timer for display
const int SHORT_PRESS_TIME = 1000;
const int LONG_PRESS_TIME = 1000;
unsigned long pressedTime = 0;
unsigned long releasedTime = 0;
bool isPressing = false;
bool isLongDetected = false;
bool isShortDetected = false;
unsigned long pressedTime2 = 0;
unsigned long releasedTime2 = 0;
bool isPressing2 = false;
bool isLongDetected2 = false;
bool isShortDetected2 = false;
ezButton button(NAVI_BUTTON); // navigation button
ezButton button2(SELECT_BUTTON); // selection button
U8G2_SSD1309_128X64_NONAME0_F_4W_SW_SPI u8g2(U8G2_R0,
/* clock=*/ 13, /* data=*/ 11, /* cs=*/ CS_DISPLAY,
/* dc=*/ DC_DISPLAY, /* reset=*/ RES_DISPLAY);
/*TEMPERATURE SENSORS*/
// Use software SPI: CS, DI, DO, CLK
Adafruit_MAX31856 engThermo = Adafruit_MAX31856(CS_ENG_TEMP_PIN, 11, 12, 13);
Adafruit_MAX31856 heaterThermo = Adafruit_MAX31856(CS_HEATER_TEMP_PIN, 11, 12, 13);
/*Engine Temp*/
struct {
double coldJunction = 0;
double head = 0;
} engineT;
/*Heater Temp and Heater*/
struct {
double coldJunction = 0;
double head = 0;
int atTemp = 0;
int heaterSetPoint = 0;
char heaterTemp[6];
} heaterT;
/*SYSTEM POWER*/
const double voltage_lsb = 0.003125;
const double current_lsb = 0.001068115; // 1.365 milli ohm shunt resistor
/*
need to do calculations for a 1 milli ohm shunt resistor
for const double current_lsb
*/
//const double current_lsb = 0.0000305;
/*----OUTPUT POWER SENSOR----*/
double OUTvoltage, OUTcurrent, OUTpower;
byte OUTv1, OUTv2;
double OUTvoltageBytes, OUTcurrentBytes;
byte OUTc1, OUTc2;
/*----CHARGE POWER SENSOR----*/
float CHARGEvoltage, CHARGEcurrent, CHARGEpower;
float CHARGEv1, CHARGEcurrentBytes;
byte CHARGEc1, CHARGEc2;
/*SPI SETUP FOR INA239 PWR SENSOR*/
/*Data is shifted out on Rising edge SCK
and
Data is sampled on Falling edge SCK
*/
SPISettings INA239_settings(1000000, MSBFIRST, SPI_MODE1);
void mainDisplay(int heaterTempInt) {
u8g2.clearBuffer(); // clear the internal memory
u8g2.drawLine(75, 0, 75, 64);
u8g2.drawLine(76, 19, 128, 19);
u8g2.drawLine(76, 42, 128, 42);
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(0, 6, "WATTS"); // write something to the internal memory
u8g2.setFont(u8g2_font_profont29_tf); // 15 pixel font
u8g2.drawStr(0, 29, mDisplay.myPower);
//u8g2.drawStr(0, 29, itoa(heaterTempInt, heaterT.heaterTemp, 10));
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(0, 51, "HOURS");
u8g2.setFont(u8g2_font_t0_17b_tf); // 12 pixel font
u8g2.drawStr(0, 64, mDisplay.totalHours);
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(40, 51, "VOLTS");
u8g2.setFont(u8g2_font_t0_17b_tf); // 12 pixel font
u8g2.drawStr(40, 64, mDisplay.outputVoltage);
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(80, 6, "Quiet");
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(80, 16, "Auto Off");
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(80, 28, "Fuel(%)");
u8g2.setFont(u8g2_font_t0_17b_tf); // 12 pixel font
u8g2.drawStr(80, 41, mDisplay.myFuel);
u8g2.setFont(u8g2_font_5x8_tf); // 5 pixel font
u8g2.drawStr(80, 51, "IntBatt(%)");
u8g2.setFont(u8g2_font_t0_17b_tf); // 12 pixel font
u8g2.drawStr(80, 64, mDisplay.intBattery);
u8g2.sendBuffer(); // transfer internal memory to the display
}
void settingsDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "RUNTIME: 23Hr"); //
u8g2.sendBuffer(); // transfer internal memory to the display
}
void runtimeDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "RUNTIME: 23 Hr"); //
u8g2.sendBuffer(); // transfer internal memory to the display
}
void modeDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "MODE: QUIET");
u8g2.sendBuffer();
}
void outputVoltageDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "OUTPUT V: 14V");
u8g2.sendBuffer();
}
void autoOnOffDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "AUTO OFF: ON/OFF 5 MIN");
u8g2.sendBuffer();
}
void intBattDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(0, 6, "INT BATT: ");
u8g2.drawStr(50, 6, "SOC");
u8g2.drawStr(66, 6, mDisplay.intBattery);
u8g2.drawStr(76, 6, "%");
u8g2.drawStr(90, 6, "SOH");
u8g2.drawStr(106, 6, mDisplay.intBattery);
u8g2.drawStr(116, 6, "%");
u8g2.sendBuffer();
}
void ezbuttonPress() {
button.loop(); // MUST call the loop() function first
button2.loop();
if (flagA == 0 && flagB == 1) {
mainDisplay(heaterT.head);
}
if (flagA == 1 && flagB == 1) {
runtimeDisplay();
}
if (flagA == 1 && flagB == 2) {
modeDisplay();
}
if (flagA == 1 && flagB == 3) {
outputVoltageDisplay();
}
if (flagA == 1 && flagB == 4) {
autoOnOffDisplay();
}
if (flagA == 1 && flagB == 5) {
intBattDisplay();
}
if (button.isPressed()) {
pressedTime = millis();
isPressing = true;
isLongDetected = false;
isShortDetected = false;
}
if (button2.isPressed()) {
pressedTime2 = millis();
isPressing2 = true;
isLongDetected2 = false;
isShortDetected2 = false;
}
if (isPressing == true && flagA == 1 && isShortDetected == false) {
releasedTime = millis();
long pressDuration = releasedTime - pressedTime;
if (pressDuration < SHORT_PRESS_TIME && button.isReleased()) {
Serial.println("A short press is detected");
isShortDetected = true;
flagB++;
if (flagB > 5) {
flagB = 1;
}
Serial << flagA << endl;
Serial << flagB << endl;
}
}
if (isPressing == true && isLongDetected == false) {
long pressDuration = millis() - pressedTime;
if (pressDuration > LONG_PRESS_TIME && button.isReleased()) {
Serial.println("A long press is detected");
isLongDetected = true;
flagA++;
if (flagA > 1) {
flagA = 0;
flagB = 1;
}
Serial << flagA << endl;
Serial << flagB << endl;
}
}
}
void dataCollector() {
// if (taskTimer >= displayTimer) {
// taskTimer = 0;
if (mDisplay.power > 99) {
mDisplay.power = 0;
mDisplay.operationalHours = 0;
mDisplay.voltage = 0;
mDisplay.fuel = 0;
mDisplay.insideBattery = 0;
}
else {
itoa(mDisplay.power, mDisplay.myPower, 10);
itoa(mDisplay.operationalHours, mDisplay.totalHours, 10);
itoa(mDisplay.voltage, mDisplay.outputVoltage, 10);
itoa(mDisplay.fuel, mDisplay.myFuel, 10);
itoa(mDisplay.insideBattery, mDisplay.intBattery, 10);
}
mDisplay.power++;
mDisplay.operationalHours++;
mDisplay.voltage++;
mDisplay.fuel++;
mDisplay.insideBattery++;
// }
}
void readID_outPower() {
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_OUTPUT_V_I_SENSOR, LOW);
SPI.transfer(0x3E << 2 | 0x01);
byte m1 = SPI.transfer(0x00);
byte m2 = SPI.transfer(0x00);
Serial << m1 << " " << m2 << endl;
digitalWrite(CS_OUTPUT_V_I_SENSOR, HIGH);
SPI.endTransaction();
}
void readID_chargePower() {
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_CHARGE_V_I_SENSOR, LOW);
SPI.transfer(0x3E << 2 | 0x01);
byte m1 = SPI.transfer(0x00);
byte m2 = SPI.transfer(0x00);
Serial << m1 << " " << m2 << endl;
digitalWrite(CS_CHARGE_V_I_SENSOR, HIGH);
SPI.endTransaction();
}
void writeShuntCal_outPower(void) {
/*--- OUTPUT POWER ---*/
/*
function to write calibration value based on the shunt resistor used.
must transfer to register in hexidecimal.
*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_OUTPUT_V_I_SENSOR, LOW); //turn on spi device 1
SPI.transfer(0x02 << 2 | 0x00); //SHUNT_CAL REGISTER; SET TO MEASURE <= 35A. OUTPUT SHUNT RESISTANCE: 1.333mOHM
SPI.transfer(0x04);
SPI.transfer(0xAE); //0x04AE = 1198
digitalWrite(CS_OUTPUT_V_I_SENSOR, HIGH);
SPI.endTransaction();
}
void writeShuntCal_chargePower(void) {
/*--- CHARGER POWER ---*/
/*
function to write calibration value based on the shunt resistor used.
must transfer to register in hexidecimal.
*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_CHARGE_V_I_SENSOR, LOW); //turn on spi device 1
SPI.transfer(0x02 << 2 | 0x00); //SHUNT_CAL REGISTER; SET TO MEASURE <= 35A. OUTPUT SHUNT RESISTANCE: 1.365mOHM
SPI.transfer(0x04);
SPI.transfer(0xAE); //0x04AE = 1198
digitalWrite(CS_CHARGE_V_I_SENSOR, HIGH);
SPI.endTransaction();
}
void readVoltage_outPower(void) {
/*--- OUTPUT POWER ---*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_OUTPUT_V_I_SENSOR, LOW); // turn on spi device 1
SPI.transfer(0x05 << 2 | 0x01); //register to read
OUTv1 = SPI.transfer(0x00);
OUTv2 = SPI.transfer(0x00);
digitalWrite(CS_OUTPUT_V_I_SENSOR, HIGH); // turn off spi device 1
SPI.endTransaction();
OUTvoltageBytes = ((uint32_t)OUTv1 << 8 | OUTv2);
OUTvoltage = (OUTvoltageBytes) * (voltage_lsb);
}
void readCurrent_outPower(void) {
/*--- OUTPUT POWER ---*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_OUTPUT_V_I_SENSOR, LOW);
SPI.transfer(0x07 << 2 | 0x01);
OUTc1 = SPI.transfer(0x00);
OUTc2 = SPI.transfer(0x00);
digitalWrite(CS_OUTPUT_V_I_SENSOR, HIGH);
SPI.endTransaction();
OUTcurrentBytes = ((uint32_t)OUTc1 << 8 | OUTc2);
OUTcurrent = ((OUTcurrentBytes) * (current_lsb)) * (1.25);
}
void readVoltage_chargePower(void) {
/*--- CHARGER POWER ---*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_CHARGE_V_I_SENSOR, LOW); // turn on spi device 1
SPI.transfer(0x05 << 2 | 0x01); //register to read
CHARGEv1 = SPI.transfer16(0);
digitalWrite(CS_CHARGE_V_I_SENSOR, HIGH); // turn off spi device 1
SPI.endTransaction();
CHARGEvoltage = (CHARGEv1) * (voltage_lsb);
}
void readCurrent_chargePower(void) {
/*--- CHARGER POWER ---*/
SPI.beginTransaction(INA239_settings);
digitalWrite(CS_CHARGE_V_I_SENSOR, LOW);
SPI.transfer(0x07 << 2 | 0x01);
CHARGEc1 = SPI.transfer(0x00);
CHARGEc2 = SPI.transfer(0x00);
digitalWrite(CS_CHARGE_V_I_SENSOR, HIGH);
SPI.endTransaction();
CHARGEcurrentBytes = (CHARGEc1 << 8 | CHARGEc2);
CHARGEcurrent = ((CHARGEcurrentBytes) * (current_lsb)) * (1.25);
}
float readPower_ManualCalculation_outPower() {
/*--- OUTPUT POWER ---*/
OUTpower = (OUTvoltage * OUTcurrent);
return OUTpower;
}
float readPower_ManualCalculation_chargePower() {
/*--- CHARGER POWER ---*/
CHARGEpower = (CHARGEvoltage * CHARGEcurrent);
return CHARGEpower;
}
void measureEngTemperature() {
/*--- ENGINE TEMPERATURE ---*/
engineT.coldJunction = engThermo.readCJTemperature();
engineT.head = engThermo.readThermocoupleTemperature();
}
void measureHeaterTemperature() {
/*--- HEATER TEMPERATURE ---*/
/*trigger a conversion, returns immediately*/
heaterT.coldJunction = heaterThermo.readCJTemperature();
heaterT.head = heaterThermo.readThermocoupleTemperature();
}
void setup() {
/*INPUT SETUP*/
pinMode(NAVI_BUTTON, INPUT_PULLUP);
pinMode(SELECT_BUTTON, INPUT_PULLUP);
pinMode(HEATER_ON_OFF, OUTPUT);
/*OUTPUT SETUP*/
pinMode(HEATER_ON_OFF, OUTPUT);
pinMode(CS_OUTPUT_V_I_SENSOR, OUTPUT);
pinMode(CS_CHARGE_V_I_SENSOR, OUTPUT);
pinMode(CS_DISPLAY, OUTPUT);
digitalWrite(HEATER_ON_OFF, LOW);
digitalWrite(CS_OUTPUT_V_I_SENSOR, HIGH);
digitalWrite(CS_CHARGE_V_I_SENSOR, HIGH);
digitalWrite(CS_DISPLAY, HIGH);
/*SETUP BEGINS*/
u8g2.begin(); // display
engThermo.begin(); // thermocouple engine
heaterThermo.begin(); // thermocouple heater
/*u8g2, engThermo, heaterThermo begins need to
occur BEFORE Serial and SPI begin for the current sensor to work.
*/
Serial.begin(115200); // TEENSY 4.1
Wire1.begin(); // using I2C Wire1 for SMBUS battery communication
SPI.begin(); // spi devices
/*u8g2, engThermo, heaterThermo begins need to
occur AFTER Serial and SPI begin for the display to work.
*/
// u8g2.begin();
// engThermo.begin();
// heaterThermo.begin();
/*TEMPERATURE SETUP*/
Serial.println("MAX31856 thermocouple test");
// if ((!engThermo.begin()) && (!heaterThermo.begin())) {
// Serial.println("Could not initialize thermocouple.");
// while (1) delay(10);
// }
engThermo.setThermocoupleType(MAX31856_TCTYPE_K);
Serial.print("Thermocouple type: ");
switch (engThermo.getThermocoupleType() ) {
case MAX31856_TCTYPE_B: Serial.println("B Type"); break;
case MAX31856_TCTYPE_E: Serial.println("E Type"); break;
case MAX31856_TCTYPE_J: Serial.println("J Type"); break;
case MAX31856_TCTYPE_K: Serial.println("K Type"); break;
case MAX31856_TCTYPE_N: Serial.println("N Type"); break;
case MAX31856_TCTYPE_R: Serial.println("R Type"); break;
case MAX31856_TCTYPE_S: Serial.println("S Type"); break;
case MAX31856_TCTYPE_T: Serial.println("T Type"); break;
case MAX31856_VMODE_G8: Serial.println("Voltage x8 Gain mode"); break;
case MAX31856_VMODE_G32: Serial.println("Voltage x8 Gain mode"); break;
default: Serial.println("Unknown"); break;
}
heaterThermo.setThermocoupleType(MAX31856_TCTYPE_K);
Serial.print("Thermocouple type: ");
switch (heaterThermo.getThermocoupleType() ) {
case MAX31856_TCTYPE_B: Serial.println("B Type"); break;
case MAX31856_TCTYPE_E: Serial.println("E Type"); break;
case MAX31856_TCTYPE_J: Serial.println("J Type"); break;
case MAX31856_TCTYPE_K: Serial.println("K Type"); break;
case MAX31856_TCTYPE_N: Serial.println("N Type"); break;
case MAX31856_TCTYPE_R: Serial.println("R Type"); break;
case MAX31856_TCTYPE_S: Serial.println("S Type"); break;
case MAX31856_TCTYPE_T: Serial.println("T Type"); break;
case MAX31856_VMODE_G8: Serial.println("Voltage x8 Gain mode"); break;
case MAX31856_VMODE_G32: Serial.println("Voltage x8 Gain mode"); break;
default: Serial.println("Unknown"); break;
}
button.setDebounceTime(50); // set debounce time to 50 milliseconds
button2.setDebounceTime(50); // set debounce time to 50 milliseconds
mainDisplay(heaterT.head); // set the main display as the startup display
/*wait for serial port to connect. Needed for native USB port only*/
// while (!Serial) {
// ;
// }
}
/*----------------------------VOID LOOP--------------------------*/
void loop() {
dataCollector();
ezbuttonPress();
/* POWER BOARD TESTING */
//readID_outPower(0x3E, 2);
readID_outPower();
writeShuntCal_outPower();
readVoltage_outPower();
readCurrent_outPower();
Serial << OUTvoltage << " " << OUTcurrent << " " << readPower_ManualCalculation_outPower() << endl;
Serial << "------------" << endl;
delay(500);
}