Two MCUs, one SD card (SPI +Serial?)

Hi guys, I am facing a bit of a problem, not sure how to tackle it…

I have an ESP32 with a display and an SD card. I would like to access the contents of the SD card via wifi, but due to the display I can’t use wifi on the ESP32 (the display relies on adc2 pins)

To get around this I plan to use an esp8266 as the access point and to host the website.

Some research suggests multi-master SPI is not a thing, which leaves me with Serial.

The webpage would be a basic file explorer to view the .txt files saves on the SD.

Is it possible?

Huh?

With extra logic hardware it might be possible, but I doubt if it will work.
Can you keep the ESP32 as the main board ? If nothing else is possible, then perhaps the display can be put on another board. That would be a peculiar solution, but you have a peculiar problem.

What is wrong with the display ? Which display is it and why should it use the ADC2 pins ?

PaulRB: Huh?

Read about the ADC2 pins: https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

Note: ADC2 pins cannot be used when Wi-Fi is used. So, if you’re using Wi-Fi and you’re having trouble getting the value from an ADC2 GPIO, you may consider using an ADC1 GPIO instead, that should solve your problem.

I see. Wierd restriction! What’s the explanation?

Also why would a display need to use analog inputs?

The ESP32 has many pins and many are already in use. Sometimes even the pins for the memory are made available on a board with the note that they can not be used. The pins with the special boot conditions are also made available as normal pins. All that pin weirdness is in my opinion the major disadvantage of the ESP32.

Here are some pics of my display and board, as you can see the pins overlap. All the pins labeled adc2 stop working with WiFi enabled.

The goal is to have a Webserver on the esp8266 which somehow kind of fetches the data from the SD card via the ESP32. I was thinking this could be done via serial or I2c.

Is wthere some way I could use functions that are already available in the SD library, and instead of serial.print I just use serial.write?

Will that display work with the ESP32 ? Can you find someone who has that combination working ? Are the libraries for that display compatible with the ESP32 ?

Lets rewind a bit…

So the display and esp32 are working perfectly, there is absolutley no problem there.

The sd-card shield built into the display is also working, I am able to save my data logs to it.

I am currenlty working on setting up wifi capability in order to access the data logs stored on the sd card via wifi.

Because the display uses a paralell interface I cant get around not using ADC2 pins, which means I cannot use built in wifi, otherwise some of the pins the display relies on stop working.

Some info about the logs:

They are .txt files with 15 values, each value is stored on a new line.

I want to access these log files via wifi. It would be ideal to be able to download the logs from wifi, but at a bare minimum I would like to see the contents of the log via wifi.

Is there any was to transfer either the .txt files, or the contents of the .txt files, from the esp32 to the esp8266?

Thank you, I didn’t understand that it was already working. Very nice !

Yes, for example Serial/UART communication. But that also requires pins.

Did you buy that board, so the display can be plugged into it ? So that was the start of this chain of events that causes the problem ?

Would it be possible to redirect the ADC2 pins to other pins ? Do you know which are actually used by the display ?
There is a row of three extra I/O pins. Those can be used.
Does the library that you use allow, for example, 4-bit wide data ?

What if you use the combination of ESP32 + display as some kind of “display unit” ? Make an other board the controller and send commands via a serial port to the “display unit”.
Then you have created your own smart serial display. To understand what I mean, google for: HMI display

I chose the esp32 for its large progmem actually (and spiffs!), an uno has waaay too little memory to run the GUISlice library, and a Mega has a large footprint. The bonus of using the ESP32 is its also available in an Uno type layout, making the display shield plug and play (well almost)…

The extra pins you mention are currently used as pins 34-39 are input only. I had to run some wires to connect three display pins to the three extra pins, and the input only pins are now used for external input (I have 3 buttons for navigation, so you dont need to use touch if you have dirty hands).

Left over are Tx, Rx, IO0, I036, and the I2c pins.

There are some sample sketches available for the SD library that print the contents of the sd card to the serial monitor. Is there some way to do the same thing but send it to the serial pins instead of to the monitor?


/*
  Listfiles

  This example shows how print out the files in a
  directory on a SD card

  The circuit:
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe
  modified 2 Feb 2014
  by Scott Fitzgerald

  This example code is in the public domain.

*/
#include <SPI.h>
#include <SD.h>

File root;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("/");

  printDirectory(root, 0);

  Serial.println("done!");
}

void loop() {
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

Could I do the same kinda thing and just replace serial.print() with serial.write()?

I think this might make things even more complicated. The device takes readings from various sensors on the i2c bus and displays realtime data. The data can also be frozen on screen and saved to the sd card.

You can take a look at my first prototype here:

As you can see the library dependencies and so on would probably make it terribly difficult to to do things in the other direction.

Serial.write() is the basic function. The Serial.print() and Serial.println() is an extra class on top of that.

No HMI display ? then you get something like the Arduino boards with Wifi.

Have a look at the MKR Wifi. It has a uBlox NINA-W10 module for Wifi. Inside that NINA-W10 module is a ESP32.

What about the Uno Wifi ? It has a ESP8266 with firmware and a library on the Uno communicates with that firmware.

However, I don’t know much about those board. I don’t know if you can put that firmware on any ESP8266 board and if the library works on a ESP32.
You could make something yourself, but it already exists :confused:

Is seems that you want to do more than the standard firmware, for example running a website. So perhaps you have to write your own sketch for the ESP8266 anyway.

Select the highest possible baudrate between them. I think they can go a lot faster than 115200 baud. I would be nice to have a protocol, so the receiver knows where the end of the data is.

There are probably good ways and libraries that support this kind of data transfer, but at the moment nothing pops into my mind.

I have given it a lot more thought.

I have a limited number of logs, 12 directories, each directory contains 12 logs (/car_1/log_12.txt for example).

And I know the contents of each log will be the same size (~100 characters, give or take a few).

My proposed solution would work like this:

  • The ESP8266 sends a char array containing the directory and log name via serial.

  • The ESP32 receives this char array via serial, and uses it in the char array as the directory for SD.open()

  • The contents of the .txt file are read and stored in another char array, and sent back via serial to the esp8266.

  • This char array can then be used for whatever purpose on the esp8266.

Some things I need help with:

  • How do the microcontrollers know when is the start and end of each transmission?
  • How to mark the start and end of each line in the char array? \n?

Microcontrollers don’t know :wink:

Maybe reading Serial Input Basics - updated might give you ideas.

1 Like

:smirk:

//Another rediculously good mod by Mick ;)

//Read sd card via serial communication (Tx and Rx pins on MCU)
//Directory to be opened is sent to this device via serial
//The file on the sd card under this directory is opened and read
//The contents are sent via serial to other device
//"<" and ">" mark begin and end of serial transmission. Everything outside of these markers is ignored.

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

const int chipSelect = 5;
const byte numChars = 100;
const char startMarker = '<';
const char endMarker = '>';
char recievedDirectory[numChars];
boolean newData = false;

void setup() {
  Serial.begin(9600);
  Serial.println("begin");
  SD.begin(chipSelect);
}

void loop() {
  recvWithStartEndMarkers();
  showNewData();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        recievedDirectory[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        recievedDirectory[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("Contents of directory:");
    Serial.println(recievedDirectory);
    File logFile = SD.open(recievedDirectory);
    // if the file is available, show contents:
    if (logFile) {
      Serial.write(startMarker);
      while (logFile.available()) {
        Serial.write(logFile.read());
      }
      Serial.write(endMarker);
      logFile.close();
    }
    newData = false;
  }
}