Bit-banged SPI conflicting with SPI.h and SD.h library (NHD-0420CW-Ax3 display)
I have been doing well to solve my own problems but this one has me stumped.
I have developed my code so far successfully using SD.h for the SD card and Wire.h for the RTC and display until I decided to make the display work over SPI instead.
Of all the SPI code examples I have found for the display the only one I have made work is the big-banged one in my sketch, however if SD.h or SPI.h are included in the code the screen doesn't do anything - a previous working sketch's output will remain frozen on the screen after upload. Remove SPI/SD.h and the display works again.
I have taken a look over SD.h and SD.cpp, as well as the many others included in that library but nothing jumps out at me and it is going over my head.
/* Datalogger v0.93.3 for Arduino Mega2560, NHD-0420CW-Ax3, DS3231 and SD card - 8% progmem; 19% SRAM
*
* The circuit:
* OLED pin 7 (SCK) to Arduino pin 52 (SCK)
* OLED pin 8 (MOSI) to Arduino pin 51 (MOSI)
* OLED pin 9 (MISO) to Arduino pin 50 (MISO)
* OLED pin 15 (CS) to Arduino pin 29 (CS)
* OLED pin 16 (/RES) to Arduino pin 36 // Reset or VDD 5V (or to Arduino pin D13, to control reset by sw)
* MISO to ICSP pin 1 / 50
* MOSI to ICSP pin 4 / 51
* CLK to ICSP pin 3 / 52
* SDcard CS to pin 31
* Arduino Pin 20 to I2C SDA w/ 10K pull-up
* Arduino Pin 21 to I2C SCL w/ 10K pull-up
* Original example created by Newhaven Display International Inc.
* Modified and adapted 15 Mar 2015 by Pasquale D'Antini
* Modified 19 May 2015 by Pasquale D'Antini
* Further modified and added to by DataL
* This example code is in the public domain.
*/
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#define DS3231_I2C_ADDRESS 0x68
int count; // Process loop couter
//----- For the inputs:
//Analog
#define muxPin A0 // sensor mux input
#define otsPin A2 // sensor OTS input
#define opsPin A4 // sensor OPS input
#define iatPin A6 // sensor IAT input
int svpValue; // sensor supply voltage value
int svnValue; // sensor supply earth value
int mpsValue; // sensor MPS value
int otsValue; // sensor OTS value
int opsValue; // sensor OPS value
int iatValue; // sensor IAT value
int otsTemp; // Engine Oil Temperature in Celcius
int opsPres; // Engine Oil Pressure
int iatTemp; // Inlet Air Temperature
int mpsPres; // Manifold Pressure
//Digital
#define muxaPin 34 // multiplexer control A
#define muxbPin 36 // multiplexer control B
#define muxcPin 38 // multiplexer control C
#define ignPin 02 // voltage IGN input
#define dosPin 04 // voltage DOS input
int ignValue; // binary Ignition On value
int dosValue; // binary Door Open Switch value
//----- For the sensor calculations:
int svpVolt; // sensor supply voltage
int svnVolt; // sensor earth voltage
int mpsVolt; // sensor MPS voltage
int otsVolt; // sensor OTS voltage
int opsVolt; // sensor OPS voltage
int iatVolt; // sensor IAT voltage
int otsRes; // sensor OTS resistance
double iatRes; // sensor IAT resistance
double otsTempK; // Engine Oil Temperature in Kelvin
double iatTempK; // Inlet Air Temperature in Kelvin
//Sensor averages
int i = 0;
long svpAve;
long svnAve;
long svdAve;
long mpsAve;
long otsAve;
long opsAve;
long iatAve;
//-----For the SPI Comms
#define SCLK 52
#define MOSI 51
#define MISO 50
#define sdCS 31 // SD card SPI Chip Select pin
#define lcdCS 29 // LCD screen SPI Chip Select pin
//----- For the SD card:
File mainLog;
//File faultLog;
//----- For the LCD screen:
//Setup
#define COLUMN_N 20 // Number of display columns
#define ROW_N 4 // Number of display rows
#define lcdRes 44 // Reset LCD screen when LOW
byte new_line[4] = {0x80, 0xA0, 0xC0, 0xE0}; // Maybe 0x01?? // DDRAM address for each line of the display (128, 160, 192, 224)
byte rows = 0x08; // Display mode: 2/4 lines; default (0x08 = 8)
byte r = 0; // Row index
byte c = 0; // Column index
//Welcome arrays
const char welcome0[21] PROGMEM = "X Starting X";
const char welcome1[21] PROGMEM = " Datalogger ";
const char welcome2[21] PROGMEM = " v0.93 ";
const char welcome3[21] PROGMEM = "X X";
const char* const welcometable[] PROGMEM = {welcome0, welcome1, welcome2, welcome3};
char welcome[21];
//Output arrays
char buffer0[21];
char buffer1[21];
char buffer2[21];
char buffer3[21];
char buffer4[9];
char buffer5[9];
//----- For the power control:
#define lcdReg 46 // LCD display power supply transistor
#define perReg 03 // Peripheral power supply transistor
#define senReg 32 // Sensor power supply transistor
//----- For the date and time:
char weekDayVerb[10] = "AnyDayYet";
const char monday[7] PROGMEM = "Monday";
const char tuesday[8] PROGMEM = "Tuesday";
const char wednesday[10] PROGMEM = "Wednesday";
const char thursday[9] PROGMEM = "Thursday";
const char friday[7] PROGMEM = "Friday";
const char saturday[9] PROGMEM = "Saturday";
const char sunday[7] PROGMEM = "Sunday";
char monthVerb[4] = "AnyMonth";
const char jan PROGMEM = "Jan";
const char feb PROGMEM = "Feb";
const char mar PROGMEM = "Mar";
const char apr PROGMEM = "Apr";
const char may PROGMEM = "May";
const char jun PROGMEM = "Jun";
const char jul PROGMEM = "Jul";
const char aug PROGMEM = "Aug";
const char sep PROGMEM = "Sep";
const char oct PROGMEM = "Oct";
const char nov PROGMEM = "Nov";
const char dec PROGMEM = "Dec";
//----- For the refresh rate:
unsigned long previousMillis = 0; // will store last time logs were updated
const long interval = 1000; // interval at which to update logs (milliseconds)
void setup(void) {
count=0;
i=0;
pinMode(SCLK, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(sdCS, OUTPUT);
pinMode(lcdCS, OUTPUT);
pinMode(lcdRes, OUTPUT);
pinMode(lcdReg, OUTPUT);
pinMode(perReg, OUTPUT);
pinMode(senReg, OUTPUT);
pinMode(muxPin, INPUT);
pinMode(otsPin, INPUT);
pinMode(opsPin, INPUT);
pinMode(iatPin, INPUT);
pinMode(muxaPin, OUTPUT);
pinMode(muxbPin, OUTPUT);
pinMode(muxcPin, OUTPUT);
pinMode(ignPin, INPUT);
pinMode(dosPin, INPUT);
digitalWrite(SCLK, HIGH);
digitalWrite(MOSI, LOW);
digitalWrite(sdCS, HIGH);
digitalWrite(lcdCS, HIGH);
digitalWrite(lcdRes, HIGH); // Disable LCD reset
digitalWrite(lcdReg, HIGH); // Enable transistor
digitalWrite(perReg, HIGH); // Enable transistor
digitalWrite(senReg, HIGH); // Enable transistor
delay(1);
Wire.begin(); // Initiate the Wire library and join the I2C bus as a master
// settime(); // Use when need to reset datetime with uploading
Serial.begin(9600); // Initialize serial communication
while (!Serial){;} // Wait for serial port to connect
LCDinit();
SDinit();
Welcome();
delay(2500);
}
void loop(void) { // MAIN PROGRAM
if (!SD.exists("/MainLogs/")) {
SDinit();
}
inputs(); // Read values on input pins
calculate(); // Convert values into info
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
buffers(); // Compose output text buffers.
LCDdisplay(); // Output buffers to screen
seriallog(); // Output to serial
SDlogmain(); // Output to SD card
count = count + 1;
i = 0; // Reset mean count
svpAve = 0; // Reset means
svnAve = 0;
mpsAve = 0;
otsAve = 0;
opsAve = 0;
iatAve = 0;
previousMillis = currentMillis;
}
}
void Welcome() {
Serial.print(F("\nStarting Datalogger v0.93"));
Serial.print(F("\nCount: "));
Serial.print(count);
r = 0; // Row index
c = 0; // Column index
command(0x01); // Clears display (and cursor home)
delay(2); // After a clear display, a minimum pause of 1-2 ms is required
for (int r = 0; r < 4; r++) {
strcpy_P(welcome, (char*)pgm_read_word(&(welcometable[r])));
command(new_line[r]); // Moves the cursor to the first column of line [i]
for (c=0; c<COLUMN_N; c++) { // One character at a time,
data(welcome[c]); // Displays the corresponding string
}
}
}
void LCDdisplay() {
byte r = 0; // Row index
byte c = 0; // Column index
r = 0; // Choose line 0
command(new_line[r]); // Moves the cursor to the first column of that line
for (c=0; c<COLUMN_N; c++) { // One character at a time,
data(buffer0[c]); } // Displays the correspondig string
r = 1; // Choose line 1
command(new_line[r]); // Moves the cursor to the first column of that line
for (c=0; c<COLUMN_N; c++) { // One character at a time,
data(buffer1[c]); } // Displays the correspondig string
r = 2; // Choose line 2
command(new_line[r]); // Moves the cursor to the first column of that line
for (c=0; c<COLUMN_N; c++) { // One character at a time,
data(buffer2[c]); } // Displays the correspondig string
r = 3; // Choose line 3
command(new_line[r]); // Moves the cursor to the first column of that line
for (c=0; c<COLUMN_N; c++) { // One character at a time,
data(buffer3[c]); } // Displays the corresponding string
}
//-----For the SD card:
void SDinit(void) {
Serial.print(F("\n\nInitializing SD card... "));
if (SD.begin(sdCS)) {
Serial.print(F("SD card initialised."));
Serial.print(F("\n")); }
else {
Serial.print(F("SD card inaccessible."));
Serial.print(F("\n"));
return; }
if (SD.exists("/MainLogs/")) { // *Directory name
Serial.print(F("\n/MainLogs/ Directory exists")); } // *Directory name
else {
Serial.print(F("\n/MainLogs/ directory doesn't exist. Creating directory... ")); // *Directory name
SD.mkdir("/MainLogs/"); // *Directory name
if (!SD.exists("/MainLogs/")) { // *Directory name
Serial.print(F("\nDirectory /MainLogs/ failed to be created")); // *Directory name
return; }
else {
Serial.print(F("\nDirectory /MainLogs/ has been created")); } } // *Directory name
/* // Save the following for a later date //
if (SD.exists("/FaultLog/")) { // *Directory name
Serial.print(F("\n/FaultLog/ Directory exists")); // *Directory name
Serial.print(F("\n\n")); }
else {
Serial.print(F("\n/FaultLog/ Directory doesn't exist. Creating directory... ")); // *Directory name
SD.mkdir("/FaultLog/"); // *Directory name
if (!SD.exists("/FaultLog/")) { // *Directory name
Serial.print(F("\nDirectory /FaultLog/ failed to be created")); // *Directory name
Serial.print(F("\n\n"));
return; }
else {
Serial.print(F("\nDirectory /FaultLog/ has been created")); // *Directory name
Serial.print(F("\n\n")); }
*/
}
void SDlogmain(void) {
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // retrieve data from DS3231
char filepath[9];
snprintf (filepath, 9, "%d%d%d.csv", dayOfMonth, monthVerb, year);
Serial.print("filepath = ");
Serial.println(dayOfMonth);
mainLog = SD.open("filepath", FILE_WRITE);
if (!mainLog) {
Serial.print(F("\nSDlogmain failed to open file "));
Serial.print("filepath");
digitalWrite(42, LOW); }
else {
Serial.print(F("\nSDlogmain successfully opened file "));
Serial.print("filepath");
digitalWrite(42, HIGH); }
mainLog.println("Testing, writing, filling...");
mainLog.close();
if (!mainLog) {
Serial.print(F("\nSDlogmain successfully closed file "));
Serial.println("filepath");
Serial.println(); }
else {
Serial.print(F("\nSDlogmain failed to close file "));
Serial.println("filepath");
Serial.println(); }
mainLog = SD.open("filepath");
Serial.print("Text file contains: ");
while (mainLog.available()) {
Serial.write(mainLog.read()); }
Serial.print("\n\n");
mainLog.close();
}
//-----For The RTC Module:
//-----For the LCD screen:
void command(byte c) { // PREPARES THE TRANSMISSION OF A COMMAND BYTE
byte i = 0; // Bit index
for(i=0; i<5; i++) {
digitalWrite(MOSI, HIGH);
clockCycle();
}
for(i=0; i<3; i++) {
digitalWrite(MOSI, LOW);
clockCycle();
}
send_byte(c); // Transmits the byte
}
void data(byte d) { // PREPARES THE TRANSMISSION OF A BYTE OF DATA
byte i = 0; // Bit index
for(i=0; i<5; i++) {
digitalWrite(MOSI, HIGH);
clockCycle();
}
digitalWrite(MOSI, LOW);
clockCycle();
digitalWrite(MOSI, HIGH);
clockCycle();
digitalWrite(MOSI, LOW);
clockCycle();
send_byte(d); // Transmits the byte
}
void send_byte(byte tx_b) { // SEND TO THE DISPLAY THE BYTE IN tx_b
byte i = 0; // Bit index
for(i=0; i<4; i++) {
if((tx_b & 0x01) == 1) {
digitalWrite(MOSI, HIGH);
}
else {
digitalWrite(MOSI, LOW);
}
clockCycle();
tx_b = tx_b >> 1;
}
for(i=0; i<4; i++) {
digitalWrite(MOSI, LOW);
clockCycle();
}
for(i=0; i<4; i++) {
if((tx_b & 0x1) == 0x1) { // <------- Change (?)
digitalWrite(MOSI, HIGH);
}
else {
digitalWrite(MOSI, LOW);
}
clockCycle();
tx_b = tx_b >> 1;
}
for(i=0; i<4; i++) {
digitalWrite(MOSI, LOW);
clockCycle();
}
}
void clockCycle(void) { // EXECUTE THE CLOCK SIGNAL CYCLE
digitalWrite(lcdCS, LOW); // Sets LOW the /CS line of the display (optional, can be always low)
delayMicroseconds(1); // Waits 1 us (required for timing purpose)
digitalWrite(SCLK, LOW); // Sets LOW the SCLK line of the display
delayMicroseconds(1); // Waits 1 us (required for timing purpose)
digitalWrite(SCLK, HIGH); // Sets HIGH the SCLK line of the display
delayMicroseconds(1); // Waits 1 us (required for timing purpose)
digitalWrite(lcdCS, HIGH); // Sets HIGH the /CS line of the display (optional, can be always low)
delayMicroseconds(1); // Waits 1 us (required for timing purpose)
}
void LCDinit() {
command(0x22 | rows); // Function set: extended command set (RE=1), lines # (0x22 = 34)
command(0x71); // Function selection A: (0x71 = 113)
data(0x5C); // Enable internal Vdd regulator at 5V I/O mode (default) (0x00 for disable: 2.8V I/O) (0x5C = 92)
command(0x20 | rows); // Function set: fundamental command set (RE=0) (exit from extended command set), lines # (0x20 = 32)
command(0x08); // Display ON/OFF control: display off, cursor off, blink off (default values) (0x08 = 8)
command(0x22 | rows); // Function set: extended command set (RE=1), lines # (0x22 = 34)
command(0x79); // OLED characterization: OLED command set enabled (SD=1) (0x79 = 121)
command(0xD5); // Set display clock divide ratio/oscillator frequency: (0xD5 = 213)
command(0x70); // Divide ratio=1, frequency=7 (default values) (0x70 = 112)
command(0x78); // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set) (0x78 = 120)
command(0x09); // Extended function set (RE=1): 5-dot font, B/W inverting disabled (def. val.), 3/4 lines (0x09 = 9)
command(0x06); // Entry Mode set - COM/SEG direction: COM0->COM31, SEG99->SEG0 (BDC=1, BDS=0) (0x06 = 6)
command(0x72); // Function selection B: (0x72 = 114)
data(0x0A); // ROM/CGRAM selection: ROM C, CGROM=250, CGRAM=6 (ROM=10, OPR=10) (0x0A = 10)
command(0x79); // OLED characterization: OLED command set enabled (SD=1) (0x79 = 121)
command(0xDA); // Set SEG pins hardware configuration: (0xDA = 218)
command(0x10); // Alternative odd/even SEG pin, disable SEG left/right remap (default values) (0x10 = 16)
command(0xDC); // Function selection C: (0xDC = 220)
command(0x00); // Internal VSL, GPIO input disable (0x00 = 0)
command(0x81); // Set contrast control: (0x81 = 129)
command(0x00); // Contrast=127 (default value) (0x7F = 127)
command(0xD9); // Set phase length: (0xD9 = 217)
command(0xF1); // Phase2=15, phase1=1 (default: 0x78) (0x78 = 120)
command(0xDB); // Set VCOMH deselect level: (0xDB = 219)
command(0x40); // VCOMH deselect level=1 x Vcc (default: 0x20=0,77 x Vcc) (0x40 = 64)
command(0x78); // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set) (0x78 = 120)
command(0x20 | rows); // Function set: fundamental command set (RE=0) (exit from extended command set), lines # (0x20 = 32)
command(0x01); // Clear display (0x01 = 1)
delay(2); // After a clear display, a minimum pause of 1-2 ms is required
command(0x80); // Set DDRAM addlcdRess 0x00 in addlcdRess counter (cursor home) (default value) (0x80 = 128)
command(0x0C); // Display ON/OFF control: display ON, cursor off, blink off (0x0C = 12)
delay(250); // Waits 250 ms for stabilization purpose after display on
}
-
To answer my own question, I needed to change the arduino pins the screen was connected to as they were trying to be used for two purposes; SPI.h and sketch code.
0
Please sign in to leave a comment.
Comments
1 comment