ESP32 SPI default config
Posted: Mon Jan 13, 2020 7:42 am
Hello All
I’m using the SPI bus (VSPI) to communicate with an AD9833 chip and a TS7735 LCD display (via the arduino SPI lib), I have been able to communicate with each individually and I have also been able to communicate with the TS7735 and then the AD9833. However, I can’t communicate with the TS7735 after the AD9833, I believe that the AD9833 library I’m using is changing SPI configuration such that the TS7735 can no longer work.
Looking at the AD9833 library it uses the Arduino SPI library and the only configuration I can see is it sets the mode (SPI.setDataMode(SPI_MODE2);) I have tried setting it to all the other modes after the AD9833 communication has finished but I still can’t talk to the TS7735 after the AD9833. I have tried looking at the TS7735 library (Adafruit_ST7735.cpp and .h files) I’m using to see how it configures the SPI bus but can’t seem to find where it does it (I’m fairly new to Cpp and the ESP32).
I have also tried instantiating the TS7735 object after talking to the AD9833 which doesn’t help, for this reason, my thinking is that the TS7735 lib doesn’t set its SPI config but just works with the default (which gets changed when the AD9833 lib runs).
I would greatly appreciate it if someone could share some thoughts on what the issue might be or how I can find the SPI config that the ST7735 is using.
Below is the Code i'm using as well as the AD9833.cpp and AD9833.h file, the ST7735 lib can be found here
https://github.com/adafruit/Adafruit-ST7735-Library
I’m using the SPI bus (VSPI) to communicate with an AD9833 chip and a TS7735 LCD display (via the arduino SPI lib), I have been able to communicate with each individually and I have also been able to communicate with the TS7735 and then the AD9833. However, I can’t communicate with the TS7735 after the AD9833, I believe that the AD9833 library I’m using is changing SPI configuration such that the TS7735 can no longer work.
Looking at the AD9833 library it uses the Arduino SPI library and the only configuration I can see is it sets the mode (SPI.setDataMode(SPI_MODE2);) I have tried setting it to all the other modes after the AD9833 communication has finished but I still can’t talk to the TS7735 after the AD9833. I have tried looking at the TS7735 library (Adafruit_ST7735.cpp and .h files) I’m using to see how it configures the SPI bus but can’t seem to find where it does it (I’m fairly new to Cpp and the ESP32).
I have also tried instantiating the TS7735 object after talking to the AD9833 which doesn’t help, for this reason, my thinking is that the TS7735 lib doesn’t set its SPI config but just works with the default (which gets changed when the AD9833 lib runs).
I would greatly appreciate it if someone could share some thoughts on what the issue might be or how I can find the SPI config that the ST7735 is using.
Below is the Code i'm using as well as the AD9833.cpp and AD9833.h file, the ST7735 lib can be found here
https://github.com/adafruit/Adafruit-ST7735-Library
Code: Select all
#include <Arduino.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include "AD9833.h"
#include <SPI.h>
#define TFT_CS 5
#define TFT_DC 12
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_RST 14
#define squareWave 1
#define sineWave 0
#define triangleWave 2
const int FYSNC_Pin = 27; //AD9833 CS pin
const int ledPin1 = 13; //debugging LED
long masterClock_freq = 24000000;
unsigned char currentMode = 0;
unsigned long frequency1 = 100; //starting freq
unsigned long phase = 0;
char buffer[32];
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); //config pins for screen, screen CS is pin GPIO5
AD9833 sigGen(FYSNC_Pin, 24000000); //config CS and freq for AD9833
void setup(void) {
Serial.begin(9600);
Serial.print("Hello! ST77xx TFT Test");
// Use this initializer if using a 1.8" TFT screen:
tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab
Serial.println("Initialized");
uint16_t time = millis();
tft.fillScreen(ST77XX_BLACK);
time = millis() - time;
Serial.println(time, DEC);
delay(500);
// large block of text
tft.fillScreen(ST77XX_BLACK);
//drawtext_line1("Test Line 1", ST77XX_WHITE);
drawtext_line2("Test Line 2", ST77XX_GREEN);
pinMode(ledPin1, OUTPUT);
pinMode(FYSNC_Pin, OUTPUT);
digitalWrite(FYSNC_Pin, HIGH);
}
void loop() {
digitalWrite(ledPin1, HIGH);
delay(500);
digitalWrite(ledPin1, LOW);
delay(500);
setOutput(frequency1, sineWave); //Tell the AD9833 to change to a new frequency
delay(3000);
frequency1 += 500;
if(frequency1 > 2000){
frequency1 = 100;
}
ltoa(frequency1,buffer,10);
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); //Used to test if reinstantiating ST7735 object fixed the issue
drawtext_line3(buffer, ST77XX_RED);
Serial.println(buffer);
}
void drawtext_line1(char *text, uint16_t color) {
//tft.setCursor(10, 0);
//tft.setTextColor(color);
//tft.setTextWrap(true);
//tft.setTextSize(1.5);
//tft.print(text);
}
void drawtext_line2(char *text, uint16_t color) {
tft.setCursor(10, 25);
tft.setTextColor(color);
tft.setTextWrap(true);
tft.setTextSize(1.5);
tft.print(text);
}
void drawtext_line3(char *text, uint16_t color) {
tft.setCursor(10, 50);
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(10, 50);
tft.setTextColor(color);
tft.setTextWrap(true);
tft.setTextSize(1.5);
tft.print(text);
}
void setOutput(long frequency, int waveForm){
//digitalWrite(FYSNC_Pin, LOW); //not needed handled in AD9833 lib
sigGen.reset(1);
sigGen.setFreq(frequency);
sigGen.setFPRegister(1);
sigGen.mode(waveForm);
sigGen.reset(0);
//digitalWrite(FYSNC_Pin, HIGH);
}
Code: Select all
#include <Arduino.h>
#include <SPI.h>
#include "AD9833.h"
AD9833::AD9833(int _FSYNC, unsigned long _mclk) {
FSYNC = _FSYNC;
pinMode(FSYNC, OUTPUT); // Set FSYNC pin as input
mclk = _mclk; // Set the oscillator used, for example 24MHz
controlRegister = 0x2000; // Default control register : FREQ0, PHASE0, Sine
fqRegister = 0x4000; // Default frequency register is 0
pRegister = 0xC000; // Default phase register is 0
//SPI.begin(); // Initialise the SPI BUS
//SPI.setDataMode(SPI_MODE2); // Set SPI in mode2, this should be moved in
// methods when SPI.transfer is called in case you
// have multiple devices using the SPI bus
}
void AD9833::writeData(int data) {
// FSYNC pin must be pulled low when new data is received by AD9833
digitalWrite(FSYNC, LOW);
// Send the first 8 MSBs of data
SPI.transfer(highByte(data));
// Send the last 8 LSBs of data
SPI.transfer(lowByte(data));
// Set the FSYNC pin to high then end SPI transaction
digitalWrite(FSYNC, HIGH);
// debugging
if (debugging) {
lcdDebug(String(data, HEX));
}
}
void AD9833::setFreq(unsigned long _freq) {
// First check that the data received is fine
unsigned long freqReg;
// Frequency cannot be negative
if (_freq < 0) {
freqReg = 0;
freq = 0;
}
// If the frequency is more than maximum frequency, just set it to maximum
else if (_freq > mclk) {
freqReg = pow(2, 28) - 1;
freq = mclk / 2;
}
// If all is good, compute the freqReg knowhing that the analog output is
// (mclk/2^28) * freqReg
else {
freq = _freq;
freqReg = (freq * pow(2, 28)) / mclk;
}
// Initialise two variables that are 16bit long which we use to divide the
// freqReg in two words
// set D15 to 0 and D14 to 1 to put data in FREQ0/1 register
int MSW = ((int)(freqReg >> 14)) | fqRegister; // Take out the first 14bits
// and set D15 to 0 and D14 to
// 1 or viceversa depending on
// FREQ reg
int LSW = ((int)(freqReg & 0x3FFF)) |
fqRegister; // Take only the last 14bits using a mask and set D15 to
// 0 and D14 to 1 or viceversa depending on FREQ reg
// Send the data, most significant word first
writeData(LSW);
writeData(MSW);
}
unsigned long AD9833::getFreq() {
return freq;
}
void AD9833::setPhase(int _phase) {
// Phase cannot be negative
if (_phase < 0) {
phase = 0;
}
// Phase maximum is 2^12
else if (_phase >= 4096) {
phase = 4096 - 1;
}
// If all is good, set the new phase value
else {
phase = _phase;
}
// Extract the 12 bits from the freqReg and set D15-1, D14-1, D13-0, D12-X to
// put data in PHASE0/1 register
int phaseData = phase | pRegister;
int LSW = (phase & 0x3FFF) | pRegister;
writeData(phaseData);
}
int AD9833::getPhase() {
return phase;
}
void AD9833::setCtrlReg(unsigned long _controlRegister) {
// Just make sure that the first two bits are set to 0
controlRegister = _controlRegister & 0x3FFF;
writeCtrlReg();
}
int AD9833::getCtrlReg() {
return controlRegister;
}
void AD9833::writeCtrlReg() {
writeData(controlRegister);
}
void AD9833::sleep(int s) {
switch (s) {
case 0: {
controlRegister &= 0xFF3F; // No power-down: D7-0 and D6-0
} break;
case 1: {
controlRegister &= 0xFF7F; // DAC powered down: D7-0 and D6-1
controlRegister |= 0x0040;
} break;
case 2: {
controlRegister &= 0xFFBF; // Internal clock disabled: D7-1 and D6-0
controlRegister |= 0x0080;
} break;
case 3: {
controlRegister |=
0x00C0; // Both DAC powered down and internal clock disabled
} break;
}
// Update the control register
writeCtrlReg();
}
void AD9833::reset(int r) {
if (r == 0) {
controlRegister &= 0xFEFF; // Set D8 to 0
//SPI.setDataMode(SPI_MODE3);
//SPI.end();
}
else if (r == 1) {
controlRegister |= 0x0100; // Set D8 to 1
SPI.begin(); // Initialise the SPI BUS
SPI.setDataMode(SPI_MODE2); // Set SPI in mode2, this should be moved in
}
writeCtrlReg();
}
void AD9833::mode(int m) {
switch (m) {
case 0: {
controlRegister &= 0xFFDD; // Output sine: D5-0 and D1-0
} break;
case 1: {
controlRegister &= 0xFFDF; // Output triangle: D5-0 and D1-1
controlRegister |= 0x0002;
} break;
case 2: {
controlRegister &= 0xFFFD; // Output clock (rectangle): D5-1 and D1-0
controlRegister |= 0x0020;
} break;
}
writeCtrlReg();
}
void AD9833::setFPRegister(int r) {
if (r == 0) {
controlRegister &= 0xF3FF; // Set D11 and D10 in control register to 0
fqRegister = 0x4000; // Set D15 to 0 and D14 to 1 in a variable that will
// later choose the FREQ0 register
pRegister =
0xC000; // Set D15 to 1 and D14 to 1 and D13 to 0 for the PHASE register
} else if (r == 1) {
controlRegister |= 0x0C00; // Set D11 and D10 in control register to 1
fqRegister = 0x8000; // Set D15 to 1 and D14 to 0 in a variable that will
// later choose the FREQ1 register
pRegister =
0xD000; // Set D15 to 1 and D14 to 1 and D13 to 1 for the PHASE register
}
writeCtrlReg();
}
void AD9833::lcdDebugInit(LiquidCrystal_I2C *_debugger) {
debugger = _debugger;
debugging = true;
}
void AD9833::lcdDebug(String message) {
if (debugging) {
debugger->setCursor(0, 1);
debugger->print(message);
}
}
Code: Select all
#ifndef AD9833_H
#define AD9833_H
#include <SPI.h>
#include "LiquidCrystal_I2C.h"
class AD9833
{
public:
//Initialise the AD9833
//_FYNC is the pin on the uC where FYNC is connected
//_mclk is the frequency of the crystal generator
AD9833(int _FSYNC, unsigned long _mclk);
//Set and get for frequency
void setFreq(unsigned long _freq);
unsigned long getFreq();
//Set and get for phase
void setPhase(int _phase);
int getPhase();
//Set and get for control register
void setCtrlReg(unsigned long _controlRegister);
int getCtrlReg();
//Send data to AD9833
void writeData(int data);
//Send the control register
void writeCtrlReg();
//Update the control register with appopiate values for sleep/reset/mode
//s = 0 No power down
//s = 1 DAC powered down
//s = 2 Internal clock powered down
//s = 3 Both DAC and internal clock powered down
void sleep(int s);
//r = 0 Disable Reset
//r = 1 Enable Reset
void reset(int r);
//m = 0 Sine
//m = 1 Triangle
//m = 2 Clock (rectangle)
void mode(int m);
//r = 0 FREQ0 and PHASE0 are used
//r = 1 FREQ1 and PHASE1 are used
void setFPRegister(int r);
void lcdDebugInit(LiquidCrystal_I2C *);
void lcdDebug(String);
private:
int FSYNC; //FSYNC Pin of AD9833 has to be connected to a GPIO pin
unsigned long freq; //Output frequency
int phase; //Signal phase shift
unsigned long mclk; //External oscillator frequency
int fqRegister; //Switch between Frequency and Phase register 1/0
int pRegister;
int controlRegister;
LiquidCrystal_I2C *debugger; //Debugging stuff through I2C
bool debugging;
};
#endif