Взаимная связь ESP32 SPI

У меня есть две карты ESP32. Я хочу установить одну из этих карт как главную, а другую как подчиненную и общаться через SPI. Я делал это раньше на Arduino Uno, но не могу сделать это на ESP32. Ниже приведены мои основные и подчиненные коды, которые я просто подготовил. Я никак не могу получить то, что хочу. Кто-нибудь может помочь?

Главный код:

#include <SPI.h>

#define CS_PIN 5  // Выберите соответствующий вывод для выбора чипа (CS)

void setup() {
  Serial.begin(115200);
  SPI.begin();
}

void loop() {
  char dataToSend = 'A';
  
  digitalWrite(CS_PIN, LOW); // Начинаем общение с слейвом
  SPI.transfer(dataToSend); // Отправляем данные подчиненному устройству
  digitalWrite(CS_PIN, HIGH); // Завершаем связь с ведомым
  
  delay(2000); // Задержка для демонстрационных целей
}

Подчиненный код:

#include <SPI.h>

#define CS_PIN 5  // Выберите соответствующий вывод для выбора чипа (CS)

void setup() {
  Serial.begin(115200);
  SPI.begin();
}

void loop() {
  if (digitalRead(CS_PIN) == LOW) {  // Проверяем, что CS (выбор чипа) имеет низкий уровень, что означает, что устройство выбрано
    char receivedData = SPI.transfer(0); // Читаем полученные данные от мастера
    
    // Отображение полученных данных на последовательном мониторе
    Serial.println("Received Data: " + String(receivedData));
    
    delay(1000);  // Необязательная задержка для демонстрационных целей
  }
}

Новый код – новая проблема:

Я пытался адаптировать коды на странице https://microcontrollerslab.com/esp32-spi-communication-tutorial. -arduino/. Насколько я понимаю, для SPI используются следующие контакты: MISO-12; МОСИ-13; СКЛК-14; СС-15. Я настроил свои соединения таким же образом, но не могу получить ожидаемый результат от ведомого устройства. Он остается в ожидании на линии подчиненного устройства.

Главный код:

#include <SPI.h>

// Определите ALTERNATE_PINS для использования нестандартных контактов GPIO для шины SPI


  #define HSPI_MISO   MISO
  #define HSPI_MOSI   MOSI
  #define HSPI_SCLK   SCK
  #define HSPI_SS     SS

static const int spiClk = 1000000; // 1 МГц

//неинициализированные указатели на объекты SPI
SPIClass * hspi = NULL;

void setup() {
  //инициализируем экземпляр SPIClass, прикрепленный к HSPI
  hspi = new SPIClass(HSPI);

  //инициализируем hspi с помощью контактов по умолчанию
  //SCLK = 14, MISO = 12, MOSI = 13, SS = 15
  hspi->begin();

  pinMode(HSPI_SS, OUTPUT); //HSPI СС
}

// функция цикла выполняется снова и снова, пока не отключится питание или не будет выполнен сброс
void loop() {
  hspi_send_command();
  delay(100);
}

void hspi_send_command() {
  byte data_on = 0b00000001; // данные 1 для включения светодиода ведомого устройства
  byte data_off = 0b0000000; // данные 0, чтобы выключить светодиод подчиненного устройства
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_on);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();

  delay(1000);
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_off);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();
  delay(1000);

}
*/

Подчиненный код:

#include <ESP32SPISlave.h>

ESP32SPISlave slave;

static constexpr uint32_t BUFFER_SIZE {32};
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];

#define LED 2

void setup() {
    Serial.begin(115200);
    delay(2000);
    pinMode(LED, OUTPUT);
    // начало() после установки
    // HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> по умолчанию
    // VSPI = CS: 5, CLK: 18, MOSI: 23, MISO: 190
    slave.setDataMode(SPI_MODE0);
    slave.begin();
    // раб.begin(VSPI); // вы можете использовать VSPI вот так

    // очищаем буферы
    memset(spi_slave_tx_buf, 0, BUFFER_SIZE);
    memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}

void loop() {
    // блокируем до тех пор, пока транзакция не придет от мастера
    Serial.println("Initialize...");
    
    slave.wait(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);

    Serial.println("*********************");

    // если транзакция завершилась с мастера,
    // доступная() возвращает размер результатов транзакции,
    // и буфер автоматически обновляется
    char data;
    while (slave.available()) {
        // показываем полученные данные
         Serial.print("Command Received: ");
         Serial.println(spi_slave_rx_buf[0]);
         data = spi_slave_rx_buf[0];
         slave.pop();
    }
    if(data == 1 )
    {
        Serial.println("Setting LED active HIGH ");
        digitalWrite(LED, HIGH);
    }
    else if(data == 0 )
    {
        Serial.println("Setting LED active LOW ");
        digitalWrite(LED, LOW);
    }
}

, 👍2

Обсуждение

Здесь https://github.com/espressif/esp-idf/tree/master/examples/peripherals/spi_slave — это именно то, что вам нужно, примеры кода, предоставленные самим espressif., @M A K

Я раньше этого не пробовал, но мне нужен пример с расширением .ino, а не .c., @Enes Orhan

https://microcontrollerslab.com/esp32-spi-communication-tutorial-arduino/ вот полный пример!, @M A K

Это выглядит как хороший пример, но у меня он не работает. Я не понимаю, какие spi-соединения вы используете. Я попробовал оба подключения для ESP32, но результатов не получил., @Enes Orhan

Вам необходимо повысить уровень своих навыков программирования. Я дал вам точный ответ! с полным объяснением., @M A K

Я отредактировал свой вопрос, внес улучшения, как вы показали, но не получил никаких результатов. Вы можете помочь мне?, @Enes Orhan

Где в файлах кода определены номера контактов SPI? Соответствуют ли определения контактам gpio? Правильны ли физические соединения между микроконтроллерами?, @Erik


2 ответа


2

Для ESP32, если не указан точный вариант платы, по умолчанию используются макросы для MISO, MOSI, SCK и SS определяются следующим образом и используются для VSPI (т. е. SPI0):

static const uint8_t SS    = 5;
static const uint8_t MOSI  = 23;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 18;

Это можно увидеть в исходном коде и HSPI автоматически настраивается на использование SCLK 14, MISO 12, MOSI 13 и SS 15 при вызове SPI.begin(), см. эту часть исходный код.

Поскольку вы определили HSPI_SS как #define HSPI_SS SS, когда вы выполняете pinMode(HSPI_SS, OUTPUT);, вы фактически устанавливаете PIN-код 5 в качестве выхода, а не контакт 15, как вы думали.

Существует два способа правильной настройки порта HSPI.

  1. Что вы можете сделать, так это определить макросы следующим образом и вызвать hspi->begin();, передав вашу конфигурацию:
#define HSPI_MISO   12
#define HSPI_MOSI   13
#define HSPI_SCLK   14
#define HSPI_SS     15

void setup() {
  hspi = new SPIClass(HSPI);
  hspi->begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, HSPI_SS);
  // остальная часть вашего кода установки
}
  1. Как видно из исходного кода, показанного в приведенной выше ссылке, если вы явно не передаете контакты в качестве параметров при вызове SPI.begin(), библиотека автоматически назначит контакты в зависимости от того, используется ли VSPI (SCLK 18, MISO 19, MOSI 23, SS 5) или HSPI (SCLK 14, MISO 12, MOSI 13 и SS 15). Итак, все, что вам нужно определить, это ваш PIN-код HSPI_SS:
#define HSPI_SS     15

void setup() {
  hspi = new SPIClass(HSPI);
  hspi->begin();
  // остальная часть вашего кода установки
}
,

Большое спасибо. Мне удалось отправить строковое выражение. Ниже вы можете увидеть коды «Slave-Master», которые отправляют сообщения от «Master» к «Slave», используя строку «Hello From Master»., @Enes Orhan


1

Вы можете увидеть коды подчиненного-главного устройства, которые отправляют сообщения от главного устройства к подчиненному, используя команду «Привет от главного». строка.

Главный код:

#include <SPI.h>

#ifdef ALTERNATE_PINS
  #define VSPI_MISO   19
  #define VSPI_MOSI   23
  #define VSPI_SCLK   18
  #define VSPI_SS     5
#else
  #define VSPI_MISO   MISO
  #define VSPI_MOSI   MOSI
  #define VSPI_SCLK   SCK
  #define VSPI_SS     SS
#endif

static const int spiClk = 1000000; // 1 МГц

char input;

const int size_arr = 25;
char buf[size_arr];
String sendData = "Hello from Master";

//неинициализированные указатели на объекты SPI
SPIClass* vspi = NULL;

void setup() {
    Serial.begin(115200);
    
    vspi = new SPIClass(VSPI);
    
#ifndef ALTERNATE_PINS
    vspi->begin();
#else
    vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
#endif

    pinMode(VSPI_SS, OUTPUT); //HSPI СС

    vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
}

void loop() {
    input = Serial.read();
    
    if(input == 's'){
      sendData.toCharArray(buf, size_arr);
      spi_transmis(VSPI_SS, buf);
    }
    delay(50);
}

void send_spi(int selectPin, byte pram) {
    digitalWrite(selectPin, LOW);
    vspi->transfer(pram);
    digitalWrite(selectPin, HIGH); 
    vspi->endTransaction();
    delayMicroseconds(75);
}

void spi_transmis(int selectPin, char buf[]) {
  for (int i = 0; i < size_arr; i++) {
    send_spi(selectPin, buf[i]);
  }
  send_spi(selectPin, '\n');
}

Подчиненный код:

#include <ESP32SPISlave.h>

ESP32SPISlave slave;

static constexpr uint32_t BUFFER_SIZE { 1 };
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];

const int size_arr = 151;
char buf[size_arr];

volatile int pos = 0;
volatile bool active;
volatile bool process;

String received;

void setup() {
    Serial.begin(115200);
    slave.setDataMode(SPI_MODE0);
    slave.begin(VSPI);

    memset(spi_slave_tx_buf, 0, BUFFER_SIZE);
    memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}

void loop() {
    recvHandle();
    spiHandler();
}

void spiHandler() {
  slave.wait(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
    
  while (slave.available()) {
      char c = spi_slave_rx_buf[0];
      if (c == '\n') {
        buf[pos] = '\0';
        process = true;
      } else {
        buf[pos++] = c;
      }
      slave.pop();
  }
}

void recvHandle() {
  if (process) {
    received = String(buf);
    process = false;
    pos = 0;
    Serial.println(received);
    delayMicroseconds(20);
  }
}
,