How to use SPI with ESP32 and Arduino - arduino

I'm trying to send out data from SPI, but can't get it to work. There appear no data on the SPI ports (D12, 13, 14; checked with an oscilloscope) and the ESP32 seems to hang. I would like to use the HSPI port.
I am also wondering whether I need a special driver for SPI to work on ESP32 and if so, how can I check if I already have that and how do I install it. When I look in the library manager, I see no special SPI driver.
I have tried using this program (copied from https://diyi0t.com/spi-tutorial-for-arduino-and-esp8266/). It's apparently intended for esp8266. Should it work out of the box also for ESP32?
#include "SPI.h"
char buff[]="Hello Slave\n";
void setup() {
SPI.begin();
}
void loop() {
for(int i=0; i<sizeof buff; i++)
{
SPI.transfer(buff[i]);
}
delay(1000);
}
and also with this program:
#include "SPI.h"
char buff[]="Hello Slave\n";
SPIClass SPI1(HSPI);
void setup() {
SPI1.begin();
SPI1.setClockDivider(80);
}
void loop() {
for(int i=0; i<sizeof buff; i++)
{
SPI1.transfer(buff[i]);
}
delay(1000);
}
I am using a 30 pin ESP32 dev board, Arduino version 1.8.13. In preferences-->more board managers, it says:
http://arduino.esp8266.com/stable/package_esp8266com_index.json, https://dl.espressif.com/dl/package_esp32_index.json

For ESP32, you need to declare which SPI instance you want to use, like so:
#include <SPI.h>
SPIClass SPI1(HSPI);
SPI1.begin();
// Optional
// SPI1.beginTransaction(SPISettings(3000000, MSBFIRST, SPI_MODE2));
The rest is the same as ESP8266

#include <SPI.h>
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_CS 15
static const int spiClk = 240000000; // 1 MHz
SPIClass * hspi = NULL;
char buff[]="Hello Slave\n";
//byte buff[] = {0xAA, 0xBB, 0xAA, 0x01,
0x89, 0xAB, 0xCD, 0xEF};
void setup() {
Serial.begin(9600);
hspi = new SPIClass(HSPI);
hspi->begin();
hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS); //SCLK, MISO, MOSI, SS
pinMode(HSPI_CS, OUTPUT); //HSPI SS
}
void loop() {
for(int i=0; i<sizeof buff; i++)
{
SPI.transfer(buff[i]);
Serial.println(buff[i]);
}
delay(1000);
}

Assuming that you use the ESP32 Arduino Core, under the docs it is written that SPI is has a suppported Arduino API implementation. Thus using the Arduino SPI API, it should work, like all other devices (the ESP32 Arduino Core implementation conforms to the API defined by Arduino, of course I would check if your board's pinout corresponds to the Espressif defined ESP32 pinout).
If you want to see some examples, you can find one here. All supported APIs have examples on the ESP32 Arduino Core repo on GitHub.
I also want to point out that in the Arduino IDE (or the VSCode plugin) you can find examples for SPI, I would take a look as well for that.

Related

How to connect MAX30100 pulse sensor to a different i2c pins of ESP32 and read data?

I'm using a ESP32 30 pin board, MAX30100 pulse sensor for my project.
I can interface this sensor to ESP32's different i2c pins i.e. not default pins(21,22).
But I don't know how to read data from the MAX30100 if it connected to different pins - (Let's say 32, 33)
This is the program I used for default i2c pins to read data from MAX30100
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define BLYNK_PRINT Serial
#include <Blynk.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#define REPORTING_PERIOD_MS 1000
char auth[] = "*******************"; // You should get Auth Token in the Blynk App.
// Connections : SCL PIN - D1 , SDA PIN - D2 , INT PIN - D0
PulseOximeter pox;
float BPM, SpO2;
uint32_t tsLastReport = 0;
void onBeatDetected()
{
Serial.println("Beat Detected!");
}
void setup()
{
Serial.begin(115200);
pinMode(19, OUTPUT);
Blynk.begin(auth,"************", "**********");
Serial.print("Initializing Pulse Oximeter..");
if (!pox.begin()) {
Serial.println("FAILED");
for(;;);
}
else
{
Serial.println("SUCCESS");
pox.setOnBeatDetectedCallback(onBeatDetected);
}
// The default current for the IR LED is 50mA and it could be changed by uncommenting the following line.
pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
}
void loop()
{
pox.update();
Blynk.run();
BPM = pox.getHeartRate();
SpO2 = pox.getSpO2();
if (millis() - tsLastReport > REPORTING_PERIOD_MS)
{
Serial.print("Heart rate:");
Serial.print(BPM);
Serial.print(" bpm / SpO2:");
Serial.print(SpO2);
Serial.println(" %");
Blynk.virtualWrite(V3, BPM);
Blynk.virtualWrite(V4, SpO2);
tsLastReport = millis();
}
}
How do I interface MAX30100 to other pins? What should be the instructions?
PulseOximeter pox;
What does this instruction mean?
You should change direction in library:
Link to library file in github
Line 29: change that for
Wire.begin(SDA_PIN, SCL_PIN);
Where SDA_PIN and SCL_PIN are defines of your own routing.
NOTE: if you change the library you will need always to use that pins for all of your developments so maybe is better if you import that library locally or even better if you change library so if you don't pass any pin at argument it default normally I2C pins but, if defined use the defined ones.

Transmitting data between arduino's using hm-10 BLE

I am working on a project whereby I have an arduino recording the humidity and temperature levels of a room (using a DHT11 sensor), and a second arduino that recieve this data via bluetooth.
I am using the hm-10 BLE modules.
So far the data-collector can transmit data over BLE, and the reciever can recieve BLE data from my phone, but I can't figure out how to pair the two modules so that the receiver can receive data from the data-collector.
All of the solutions I have found online involve using the AT instruction set, whereas I am using the SoftwareSerial.h library.
The code for my data gatherer is as follows:
//Include the DHT (humidity and temperature sensor) library, and the serial library
#include <dht.h>
#include <SoftwareSerial.h>
//Define the constants for the input (DHT11) and output pins
#define RXpin 7
#define TXpin 8
#define DHT11_PIN 9
//Initialise a Serial channel as softSerial
SoftwareSerial softSerial(RXpin, TXpin);
//Initialise DHT object
dht DHT;
//Set initial measurement to be temperature (not humidity)
bool humidity = false;
void setup() {
//Start the serial function
Serial.begin(9600);
//Start the softSerial channel
softSerial.begin(9600);
}//void setup()
void loop() {
//Reset the reading variable
float(reading);
//Take in the values recorded by the DHT11
int chk = DHT.read11(DHT11_PIN);
//Store the necessary measurement in the reading variable
if (!humidity) {
reading = DHT.temperature;
} else {
reading = DHT.humidity;
}
//Output the reading on the softSerial channel
softSerial.print(reading);
//The DHT11 can only take one measurement per second, so waiting two seconds ensures there will be no null readings
delay(2000);
//Swap current measurement
humidity = !humidity;
}//void loop()
Any ideas on how I can connect it with another hm10 module so they can exchange information without having to re-write everything to the AT instruction set would be greatly appreciated.
You need to learn AT commands to configure the HM-10 in master or slave mode, all these can still be done using the SoftSerial library, get the HM-10 datasheet for AT commands and check these site for help.
http://www.instructables.com/id/How-to-Use-Bluetooth-40-HM10/
https://www.hackster.io/achindra/bluetooth-le-using-cc-41a-hm-10-clone-d8708e
See sample code below:
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(4, 5);
void setup() {
Serial.begin(9600);
BTSerial.begin(9600);
BTSerial.write("AT+DEFAULT\r\n");
BTSerial.write("AT+RESET\r\n");
BTSerial.write("AT+NAME=Controller\r\n");
BTSerial.write("AT+ROLE1\r\n");
BTSerial.write("AT+TYPE1"); //Simple pairing
}
void loop()
{
if (BTSerial.available())
Serial.write(BTSerial.read());
if (Serial.available())
BTSerial.write(Serial.read());
}

ISP conflict on Raspberry Pi/Arduino SPI communication

I'm working on a communication between a Raspberry Pi 3+ and an Arduino Nano. The Raspberry uses ISP pins to program the Arduino. After, both should communicate in full-duplex via SPI protocol, using the WiringPi library under Qt environment. The problem is that SPI only returns 0 on both slave and master side.
Is it possible that the ISP programmer enter in conflict with the SPI protocol, even if not used at the same time?
Master code:
GpioMachine::GpioMachine(QObject *parent) :
QObject(parent){
wiringPiSetupGpio();
wiringPiSPISetup(0,1000000);
pinMode(CE0_PIN,OUTPUT);
}
void GpioMachine::sendSPI(int channel, int cmd,int arg)
{// send 2 bytes to slave
unsigned char buffer[2];
buffer[0]=cmd;
buffer[1]=arg;
wiringPiSPIDataRW(channel,buffer,2);
int val;
val=QChar(buffer[0]).toLatin1();
int val2;
val2=QChar(buffer[1]).toLatin1();
qDebug()<<"spi get:"<<val<<val2;
}
Slave code:
#include <SPI.h>
#include "pins_arduino.h"
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c=SPDR;
Serial.println(c);
SPDR=5;// random testing value to send to master;
}
void setup()
{
Serial.begin(9600);
pinMode(MISO, OUTPUT);
pinMode(SS,INPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
SPI.attachInterrupt();
}
void loop()
{
delay(10);
}
Both codes gives only zeros. Any Idea?

Arduino SoftwareSerial Rx/Tx pin order error?

I'm writing code to run on an ATtiny being programmed by an Arduino as ISP. The ATtiny is to send AT commands over serial link to an RN42 Bluetooth module.
Since the ATtiny has no UART I'm using SoftwareSerial on pins 0 and 1. It seemed logical to put Tx on the "Data Out"/MISO pin and Rx on the "Data In"/MOSI pin. The documentation says to declare this like SoftwareSerial mySerial(Rx, Tx); but I found it only works if you declare it the other way round like SoftwareSerial mySerial(Tx, Rx);
I've taken a screenshot of my code and the pinout, I feel like I'm missing something but when I do it like this it works and makes the Bluetooth module enter command mode. Is the documentation the wrong way round?
Code and Pinout
I realised the error of my ways, I was unnecessarily setting the pinMode of the Rx and Tx pins. This threw me off as I thought setting the Rx pin to OUTPUT wouldn't work when actually it does, so I was outputting data on my Rx line and receiving it on the Tx line! The answer is to not assign direction and just let SoftwareSerial handle the pins. Pass the parameters in the order (Rx, Tx).
Here is my cleaner code that is working much better:
#include <SoftwareSerial.h>
const int Rx = 0; // pin 5 on ATtiny - DI/MOSI
const int Tx = 1; // pin 6 on ATtiny - DO/MISO
const int ButtonIn = 2;
const int OK_LED = 4;
int buttonState = 0;
SoftwareSerial serialBT(Rx, Tx);
void setup()
{
pinMode(ButtonIn, INPUT);
pinMode(OK_LED, OUTPUT);
serialBT.begin(9600);
}
void loop()
{
buttonState = digitalRead(ButtonIn);
if (buttonState == 0)
{
serialBT.print("$"); // $$$ enters RN42 command mode
serialBT.print("$");
serialBT.print("$");
delay(3000);
serialBT.println("R,1");
digitalWrite(OK_LED, HIGH);
delay(5000);
digitalWrite(OK_LED, LOW);
}
}

ESP8266 to ESP8266 i2C Communication

I am trying to get my ESP8266's connect and send messages over an i2c bus. I am using a NodeMcu Development Board. Pins D1,D2 and GND are connected to each other.
The code on my master is :
#include <Wire.h>
void setup() {
Wire.begin(D1,D2); // join i2c bus (address optional for master)
Serial.begin(115200);
}
byte x = 0;
void loop() {
Wire.beginTransmission(8);
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting
Serial.println("Transmitted");
x++;
delay(500);
}
And the code on my slave ESP is:
#include <Wire.h>
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(115200); // start serial for output
}
void loop() {
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
Serial.println("Received..");
/*
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
*/
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
Running this gives no output on the receiver chip.
As mentioned in the comments it doesn't look like I2C is supported, but you could use PJON
You just need to connect a single wire to enable communication between the two devices
I'm not sure but I would expect the Wire library from Arduino to use the hardware I2C controller for ATMega. The I2C driver in the firmware from Espressif seems to be doing I2C over GPIO, that would hint there is no hw controller on ESP (what are the odds they would be the same anyway). So you need to use something else than Wire.h, thus I would suggest - try downloading something that fakes I2C over GPIO for your Arduino IDE. Like this .. maybe, I haven't tried that out. I know not a complete solution, but maybe at least this helps.. good luck!
ESP8266(I2C Master) to ESP8266(I2C Slave) works from version 2.5.0. Check out my comments on the ESP8266 GitHub

Resources