STRCPY working with Arduino but not ESP32

In a programm for the UNO I use the following:

int buffsize = 7;
byte SERIALWriteBuffer [buffsize];
byte I2CReadBuffer [buffsize];
#define StringCopyI2CtoSERIAL() strcpy(SERIALWriteBuffer, I2CReadBuffer);

This all works fine. But now I have the UNO exchanged for an ESP32-based board.
And I get now an error like: invalid conversion from ‘byte* {aka unsigned char*}’ to ‘char*’ [-fpermissive]

Do I miss something in the strcpy syntax for the ESP32?

Hello,

You can simply cast to char *

strcpy((char*)SERIALWriteBuffer, (char*)I2CReadBuffer);

For now no errors. Only this:

sketch/InternetRF24Hub_internetside.ino.cpp.o:(.literal._Z5setupv+0x1c): undefined reference to TwoWire::onReceive(void (*)(int))' sketch/InternetRF24Hub_internetside.ino.cpp.o: In function setup()’:
/home/pi/Arduino/InternetRF24Hub_internetside/InternetRF24Hub_internetside.ino:219: undefined reference to TwoWire::onReceive(void (*)(int))' sketch/InternetRF24Hub_internetside.ino.cpp.o: In function sendback()’:
/home/pi/Arduino/InternetRF24Hub_internetside/InternetRF24Hub_internetside.ino:215: undefined reference to `TwoWire::onReceive(void (*)(int))’
collect2: error: ld returned 1 exit status
Multiple libraries were found for “SD.h”
Used: /home/pi/.arduino15/packages/esp32/hardware/esp32/1.0.6/libraries/SD
Not used: /opt/arduino-1.8.13/libraries/SD
exit status 1
Error compiling for board T-Beam

Will look later for this. Seems ESP32 has issues with strcpy command.
Thank you in advance for your quick answer.

That is a basic ‘C’ function. So I assume that it is working just fine.
If something goes wrong, then it must be something else.

On an Atmel it is working fine. There is something in the Wire-library for the ESP32 and the handling of pointers in the memory of the ESP32 is also different. Seems a tough problem at espressif. So first solutions are avoiding strcpy commands.

There is no need to avoid strcpy(), let’s find the bug :stuck_out_tongue:

Does the data received via I2C have a zero-terminator ?

Sometimes and sometimes not. Depends from where I the data get. I get data from I2C, get data from the LORA module, get data from the NRF24 module and get data from the serial port. The data format is {From, To, Instruction, data, data, data}. ‘From’ and ‘To’ are adresses similair like I2C but then as an plain protocol. So I can forward and message back. The string consist 6 bytes only. But when data is send via serial I get automatic the /r/n. Arduino can handle that to get them rid. For ESP I should use memcpy to copy the first 6 characters/bytes. But now seems only the ESP32/wire library makes problems.

#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <SD.h>

#define AdresDDS 0x01 // DDS unit
#define AdresSTM32 0x02 // Co-processor
#define AdresATMEGA 0x03 // Base
#define AdresGPS 0x04 // No external instructions needed
#define AdresUNO0 0x05 // Lora unit
#define AdresUNOLORA0 0x06 // Lora unit
#define AdresSERIAL 0x07 // For checking/debugging
#define AdresLCD 0x27 // Not mounted

#define AdresUNO1A 0x10 // IOT-box base Uno
#define AdresUNOLORA1 0x11 // IOT-box Lora unit
#define AdresUNONRF1 0x12 // IOT-box NRF unit
#define AdresUNOLCD 0x27 // IOT-box LCD

#define AdresESP1B 0x15 // IOT-box base ESP
#define AdresESPLOCAL 0x16 // IOT-box for Local instructions
#define AdresESPETH 0x17 // IOT-box WiFi
#define AdresESPINT 0x18 // IOT-box Cable
#define AdresESPSERIAL 0x19 // For checking/debugging

#define AdresUNO2 0x20 // Handheld-box base
#define AdresUNONRF2 0x21 // Handheld-box NRF unit

#define StringCopyI2CtoSERIAL() strncpy((char*)SERIALWriteBuffer, (char*)I2CReadBuffer, buffsize);
#define StringCopyI2CtoETH() strncpy((char*)ETHWriteBuffer, (char*)I2CReadBuffer, buffsize);
#define StringCopyI2CtoINT() strncpy((char*)INTWriteBuffer, (char*)I2CReadBuffer, buffsize);
#define StringCopyI2CtoLOCAL() strncpy((char*)LOCALWriteBuffer, (char*)I2CReadBuffer, buffsize);

#define StringCopySERIALtoI2C() strncpy((char*)I2CWriteBuffer, (char*)SERIALReadBuffer, buffsize);
#define StringCopySERIALtoETH() strncpy((char*)ETHWriteBuffer, (char*)SERIALReadBuffer, buffsize);
#define StringCopySERIALtoINT() strncpy((char*)INTWriteBuffer, (char*)SERIALReadBuffer, buffsize);
#define StringCopySERIALtoLOCAL() strncpy((char*)LOCALWriteBuffer, (char*)SERIALReadBuffer, buffsize);

#define StringCopyETHtoI2C() strncpy((char*)I2CWriteBuffer, (char*)ETHReadBuffer, buffsize);
#define StringCopyETHtoSERIAL() strncpy((char*)SERIALWriteBuffer, (char*)ETHReadBuffer, buffsize);
#define StringCopyETHtoINT() strncpy((char*)INTWriteBuffer, (char*)ETHReadBuffer, buffsize);
#define StringCopyETHtoLOCAL() strncpy((char*)LOCALWriteBuffer, (char*)ETHReadBuffer, buffsize);

#define StringCopyINTtoI2C() strncpy((char*)I2CWriteBuffer, (char*)INTReadBuffer, buffsize);
#define StringCopyINTtoSERIAL() strncpy((char*)SERIALriteBuffer, (char*)INTReadBuffer, buffsize);
#define StringCopyINTtoETH() strncpy((char*)ETHWriteBuffer, (char*)INTReadBuffer, buffsize);
#define StringCopyINTtoLOCAL() strncpy((char*)LOCALWriteBuffer, (char*)INTReadBuffer, buffsize);

#define StringCopyLOCALtoI2C() strncpy((char*)I2CWriteBuffer, (char*)LOCALReadBuffer, buffsize);
#define StringCopyLOCALtoSERIAL() strncpy((char*)SERIALriteBuffer, (char*)LOCALReadBuffer, buffsize);
#define StringCopyLOCALtoETH() strncpy((char*)ETHWriteBuffer, (char*)LOCALReadBuffer, buffsize);
#define StringCopyLOCALtoINT() strncpy((char*)INTWriteBuffer, (char*)LOCALReadBuffer, buffsize);

#define SerialSpeed 9600

const int buffsize = 7;
int buffcount = 0;
int buffmax = buffsize;

bool I2CReadState = LOW;
bool I2CWriteState = LOW;
byte I2CReadBuffer [buffsize];
byte I2CWriteBuffer [buffsize];

bool SERIALReadState = LOW;
bool SERIALWriteState = LOW;
byte SERIALReadBuffer [buffsize];
byte SERIALWriteBuffer [buffsize];

bool ETHReadState = LOW;
bool ETHWriteState = LOW;
byte ETHReadBuffer [buffsize];
byte ETHWriteBuffer [buffsize];

bool INTReadState = LOW;
bool INTWriteState = LOW;
byte INTReadBuffer [buffsize];
byte INTWriteBuffer [buffsize];

bool LOCALReadState = LOW;
bool LOCALWriteState = LOW;
byte LOCALReadBuffer [buffsize];
byte LOCALWriteBuffer [buffsize];

byte dataToSend[6];
byte z = 0x1F;

void setup()
{
Serial.begin(SerialSpeed);
Wire.begin(AdresESP1B);
Wire.onReceive(receiveEvent);
Serial.println(“Start”);
}

void loop() {

// Read input state
// SERIALReadState = Serial.available();

// ETHReadState = ETH.available();
// INTReadstate = INT.available();

// select if I2C was input
if (I2CReadState == HIGH)
{
Serial.print(“I2Cto”);

    if (I2CReadBuffer[0] == AdresESPETH)    // via ETH
    {
       StringCopyI2CtoETH()
       ETHWriteState = HIGH; 
    }

    if (I2CReadBuffer[0] == AdresESPINT)  // via INT
    {
       StringCopyI2CtoINT()
       INTWriteState = HIGH;  
    }

    if (I2CReadBuffer[0] == AdresESPSERIAL) // via SERIAL
    {
       StringCopyI2CtoSERIAL()
       SERIALWriteState = HIGH;
       for (buffcount = 0; buffcount < buffmax; buffcount++)
       {
        I2CReadBuffer[buffcount] = 0; 
       }
    }
    I2CReadState = LOW;
 }

///////////////////////////////////////////////////////////////////////////////////

// send to ETHernet if selected
if (ETHWriteState == HIGH)
{
ETHWriteState = LOW;
INTWriteState = LOW;
SERIALWriteState = LOW;
Serial.print(“ETH: “); // temp for test
for (buffcount = 0; buffcount < buffmax-1; buffcount++)
{
Serial.print(ETHWriteBuffer[buffcount], HEX); // temp for test
}
Serial.println(””); // temp for test

 }

// send to INTernet if selected
if (INTWriteState == HIGH)
{
ETHWriteState = LOW;
INTWriteState = LOW;
SERIALWriteState = LOW;
Serial.print(“INT: “); // temp for test
for (buffcount = 0; buffcount < buffmax-1; buffcount++)
{
Serial.print(INTWriteBuffer[buffcount], HEX); // temp for test
}
Serial.println(””); // temp for test

 }

// send to SERIAL if selected
if (SERIALWriteState == HIGH)
{
ETHWriteState = LOW;
INTWriteState = LOW;
SERIALWriteState = LOW;
Serial.print(“SERIAL: “); // temp for test
for (buffcount = 0; buffcount < buffmax-1; buffcount++)
{
Serial.print(SERIALWriteBuffer[buffcount]); // temp for test
}
Serial.println(””); // temp for test
sendback();
}

}

void receiveEvent(int howMany)
{
while (1 < Wire.available())
{
I2CReadBuffer[0] = Wire.read();
I2CReadBuffer[1] = Wire.read();
I2CReadBuffer[2] = Wire.read();
I2CReadBuffer[3] = Wire.read();
I2CReadBuffer[4] = Wire.read();
I2CReadBuffer[5] = Wire.read();
}
I2CReadState = HIGH;
}

void sendback()
{
I2CWriteBuffer[0] = z;
I2CWriteBuffer[1] = 0xAA;//random(255);
I2CWriteBuffer[2] = 0xBB;//random(255);
I2CWriteBuffer[3] = 0xCC;//random(255);
I2CWriteBuffer[4] = 0xDD;//random(255);
I2CWriteBuffer[5] = 39-z;//random(255);
z=z+1;
if (z>0x27) {z = 0x1F;}
Wire.beginTransmission(AdresUNO1A); // 0x10
Serial.print("LOCAL: ");
for (buffcount = 0; buffcount < buffmax-1; buffcount++)
{

      Serial.print(I2CWriteBuffer[buffcount], HEX); // temp for test
      Wire.write(I2CWriteBuffer[buffcount]);
    
    }
    Serial.println("<--------------"); // temp for test
    Wire.endTransmission();    // stop transmitting
    Wire.onReceive(receiveEvent);

}

I am using an Wemos R1 D32 with an Arduino Ethernet V6 shield. Separated the W5100 and SD-card with VSPI and HSPI. Also extended with extra SPIFF.

strcpy() works EXACTLY as it is supposed to on ESP32, as well as AVR. strcpy() works ONLY with null-terminated strings. There is NO reason to believe the data from I2C will be null-terminated. You should instead use memcpy, then ADD the null-terminator to the target string AFTER copying the I2C data.

So you mean in I2CWriteBuffer[6] I need to place a null-terminator 0x00
Or is it I2CWriteBuffer[6]= 0x2F and I2CWriteBuffer[7]=0x00

Looking at your data and how you use it, then I suggest to use 6 binary bytes and forget the zero-terminated string. Use memcpy() as @RayLivingston wrote.

When you want to print them, then you can no longer use Serial.print(..., HEX), you have to write a function to show the 6 bytes. That is normal for such a project.

The Serial/UART communication can of course have \r\n at the end, for synchronization. Perhaps there is something that wants a zero-terminator. But I would keep the core of your sketch with 6 bytes only.

One way or the other, you have to make a decision and stick to it.
I prefer that you explain in the sketch how the 6 bytes are defined. Can one of the bytes in the middle be zero ?

What else is connected to the I2C bus of the ESP32 ?

In the sketch, the ESP32 is both Slave and Master. That is bound to go wrong. There can be only one Master.

What is a Wemos R1 D32 ? I can not find it.

I also can not find a V6 shield.

Did you buy a ESP32 board on which a Ethershield can be attached ? The W5100 is old, it gets hot, and it uses low level Ethernet. The Wifi of the ESP32 is much more sophisticated. I think there are boards with a ESP32 and Ethernet connection.

All your #define StringCopyI2CtoSERIAL() do not make it better to read in my opinion. A memcpy() is just as easy to read.

For an UNO works perfect to have them as Slave AND Master. I had 2 UNO’s communicate together. Normalwise they both are in Slave_Receiver (as in the Arduino IDE examples for the UNO). When one of them has data to send it switching to Master_Writer mode. After that is switching back again.

I noticed already what the problem is. And that is indeed the I2C library again. Still wondering why the flush() in the ATMEL-Wire library is not programmed. But the ESP32-Wire library doesn’t know onRequest()/onReceive(). So problem is found but the solution not.

A Wemos D1 R32 is an ESP32 on a board with UNO dimensions. You can find it with Google.
The ethernet shield is a V1 rev.6 this has another schematic. And if you look at it…it fit’s perfectly
on that Wemos board. And it works perfectly include the SD-card. But for my convinence I serparated the SD spi lines. So using VSPI and HSPI ( both spi channels).
For this you need to do a little rework on the board with some smd-soldering and very thin wire.

Yes, I agree the Wifi solution is better because ESP has a good socket. But the reason for change from UNO to ESP was that I was running out of memory due variables. Beside that, I need a cabled network (maybe change the W5100 for a W5500) since it comes on a place without WiFi and the ESP is completed boxed in metal. There are some boards with ethernet adapters, but mostly still under construction. Maybe something for the future or making a board by myself.

About the project, it is divided around the 4 different units and communicating with 1 same transparant data protocol over LORA, NRF24, SERIAL and I2C.

This is the network. Hope now you understand the adressing.

And this is what I were talking about. Reason for dividing it in 2 separate boards was due speed and complexity.

And that is why I also separated the programming for an AD9910 DDS doing spreadspectrum/frequency hopping in a part for controlling (Atmega) and a part for bitbanging (STM32).

I will try to give a few ideas. Please let us know what you decide.

O, indeed :astonished: There is still no official support for Slave mode. There are libraries that can do that, but I also read there are problems with them.

Thank you for the photos and the drawing.

Could you combine a few things into one Arduino board ?
The more boards there are, the harder it is to maintain.
I’m also not a fan of using the I2C bus to communicate between Arduino boards.
Could you combine Uno 0x10 with Uno 0x15 ? Then you don’t need the I2C bus between them or a Slave mode. Or perhaps try Serial communication.
A Leonardo board has a extra hardware serial port, and adding a AltSoftSerial or SoftwareSerial can make an extra serial port.
Some use a Teensy 4.1 for the number of pins and the number of serial ports.
A MKR Zero with a MKR Ethernet shield would give enough memory + SD card + Ethernet. But it is still the low-level W5500 ethernet.

Keep in mind that you can not connect a 3.3V board to a 5V board.

In my opinion, a multi-master bus with Arduino boards is a fairy tale. It is not reliable.

I really don’t care that it works with a Uno. You have to decide how to handle those 6 or 7 bytes. You have to make a good base, so you can build you sketch upon it.

I was looking for the “R1”, ha ha.

“…Keep in mind that you can not connect a 3.3V board to a 5V board…” Sure you can if you use level shifters. When neccesary cut traces and using 0603 smd’s. Yes I can. But the UNO is special for communication between the other parts. The ESP32 I have for maintain an huge array what is a mirror from the array in the Atmega (0x03). And via a webserver I can change this. I am the only user. So local on the router here is enough. In a later stadium I only need JSON for an external webserver where others have restricted access. To give an idea of the project, there is a 4-band beacon transmitter on a high tv-tower. Like the Gebrandy Tower in Ijsselstijn, The Netherlands. Via LORA I can check and control this transmitter about 20-50km away. My IOT-box is under the roof with a cable to my router. So I can check via the website or via a handheld device with the NRF24 if everything is ok. The Atmega/STM32 board is designed by myself. The AD9912 board is also designed by myself according the Analog Devices specifications. So Ultra Low Noise supply and separated analog and digital (this is over the total project separated with 4 separated transformers). For stability I am using a 10Mhz double oven with 10x-12 for stabilizing an 1Ghz oscillator what the input frequency is for the AD9912. All packed into another oven. I am more secure then a GPS OCXO over a year. So it is a huge project almost 100% developed by myself because technical information is not availble or it is never build. And then going stuck on a @#$ I2C library :rofl:

The good new is I found an active work around on GitHub. I can test now and maybe some fixes when needed. GitHub - gutierrezps/ESP32_I2C_Slave: I2C slave library for ESP32

On the UNO I use software serial because this is for LORA (Serial1) and Serial0 the programm port I want to keep free for debugging and monitoring. But it is indeed a solution.

ETH_shield

This is the shield I am using. I have disconnect the 6-pin ICSP header. And cut some traces and removed some 4x resistors. Then with thin wire I have connected the necessary lines to the 2 headers responding for HSPI and VSPI. Also having now no IO12 problem (what is also a problem on the ESP and having perhipihals on IO12 when booting).

Due using the R1 board I was able to put extra SPIFFS memory. So the webpages with html/css/javascript are placed there. Gives me enough space to use the 6132 bytes array in RAM. In the Atmega I have this done with packing else it wouldn’t fit. The SD is only for updating the SPIFFS data.

If you are more interested PA0AG - Callsign Lookup by QRZ Ham Radio

Thank you for the background information.
Gerbrandy Tower: https://en.wikipedia.org/wiki/Gerbrandy_Tower.

I have read about I2C Slave mode libraries for the ESP32, but there seems to be trouble with it, as I wrote before. The I2C bus is not really a good communication bus between boards. Can you turn it around and make the ESP32 the Master ?
If possible, then I prefer the AltSoftSerial over SoftwareSerial on a Arduino Uno.

Did you take a good look at the Teensy 4.1 ? If you are looking for a central controller as a spider in a web, then that’s the best choice with its many serial ports.

There is indeed a timing problem. And a better solution should be if it could run only on one of the 2 cores. But I have already decide to not using I2C. Using now hardware serial2. Working perfect with the Atmel hardware serial.