Беспроводной доступ ESP32 нарушает чтение MPU9250 - PullRequest
0 голосов
/ 26 апреля 2019

Я пишу программу, которая считывает данные акселерометра и гироскопа MPU9250 с использованием внутреннего FIFO MPU9250 и обслуживает веб-интерфейс.

Без веб-доступа все нормально.

Однако при точном времени веб-запроса количество считанных байтов в этом времени изменяется.

Мой текущий код просто показывает веб-страницу шаблона и печатает значение акселерометра IMU, только если его значение превышает 2,5. Так что, если я не касаюсь датчика MPU9250, его значение должно быть в пределах 0,9 ~ 1,1. Однако при обновлении веб-страницы он выводит некоторые неправильные значения, превышающие 2,5 (в настоящее время происходит автоматическое обновление через 0,5 секунды), хотя сенсор MPU9250 вообще не затрагивается.

Я использую плату LOLIN D32 PRO. и MPU9250 подключен к шине VSPI по умолчанию.

Я читаю данные FIFO MPU 9250 о функции петли arduino следующим образом:

  while( readBytes = spiread_fifo( buffer + readBytes_all / 2 ) )
    readBytes_all += readBytes;
  if ( readBytes_all == 0 )
    return;

  if( digitalRead( 4 ) == 1 ){
  int x = buffer[ 0 ];
  int y = buffer[ 1 ];
  int z = buffer[ 2 ];
  double m = sqrt( x * x + y * y + z * z ) / 2048;
  if(  m > 2.5 )
    Serial.println( m );

и spiread_fifo определяется следующим образом

int spiread_fifo( volatile short * buffer ) {

  int fifo_len = spiread( 0x72 ) * 256 + spiread( 0x73 );

  if ( fifo_len > 512 )
    return -1;

  if ( fifo_len == 0 )
    return 0;

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( 0x74 | 0x80 );
  MPU9250.transfer( 0x00 ); // if I use SPI CLOCK more than 8~12Mhz, it gives me duplicated byte at the beginning. So just drop one of them.
  for ( int i = 0; i < 3; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  for ( int i = 3; i < fifo_len / 2; i++ )
    MPU9250.transfer16( 0x00 );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
  for ( int i = 0; i < 12; i++ )
    __asm__ __volatile__ ("nop\n\t");

  return fifo_len;
}

Если я не прикасаюсь к MPU9250 и не прилагаю к нему никаких усилий, последовательная консоль должна молчать, и это действительно происходит, если нет доступа к веб-серверу ESP32. Однако это дает случайное значение времени доступа к веб-странице, как показано ниже. (одно значение для одного доступа к веб-странице)

15.53                                                                           
16.11                                                                           
15.60                                                                           
13.59                                                                           
16.86                                                                           
2.55                                                                            
2.55                                                                            
3.85                                                                            
3.85                                                                            
3.37                                                                            
6.79                                                                            
2.63                                                                            
2.56                                                                            
5.80                                                                            
10.18                                                                           
5.88                                                                            
3.65                                                                            
5.80                                                                            
5.48                                                                            
2.95                                                                            
4.01                                                                            
4.01                                                                            
3.10                                                                            
2.90                                                                            
3.17                                                                            
9.31                                                                            
14.97                                                                           
7.08                                                                            
16.29                                                                           

, которые являются совершенно ненормальными значениями.

Мои догадки,

  1. сильный радиочастотный сигнал влияет на шину SPI, поэтому сигналы изменяются.
  2. Процедура Wi-Fi TX вызывается во время считывания FIFO MPU9250 и вызывает сбой данных во время чтения FIFO.

Какой бы ни была причина, я не знаю, как решить проблему.

Будем благодарны за любые возможные причины / решения.

Ниже моя текущая проводка. Однако ничего особенного. MPU9250 подключен к порту VSPI по умолчанию, а контакт INT подключен к GPIO34. другое оставшееся соединение не используется.

КАРТИНА 1

КАРТИНА 2

полные исходные коды ниже для справки.

ГЛАВНЫЙ КОД:

extern volatile int cnt;

volatile short* buffer;
volatile short* buffer2;
volatile unsigned long *timestamp;

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

void printHex( int num, int precision) {

  char tmp[16];
  char format[128];

  sprintf(format, "%%.%dX ", precision);

  sprintf(tmp, format, num);
  if ( strlen( tmp ) > precision + 1 ) {

    int l = strlen( tmp ) - precision - 1;
    for ( int i = 0; i < precision + 2; i++ ) {

      tmp[ i ] = tmp[ i + l ];
    }
  }

  Serial.print(tmp);
}

void setup() {

  Serial.begin( 2000000 );

  Serial.println( "Turning on...." );

  buffer = ( short * )ps_malloc( 1000000 );
  buffer2 = ( short * )ps_malloc( 1000000 );

  BUTTONSetup();
  MPU9250Setup();
  OTASetup();
  WEBSERVERSetup();

  Serial.println( "Setup finished." );
}

void loop() {

  OTAHandle();
  WEBSERVERHandle();

  int readBytes = 0, readBytes_all = 0;

  while( readBytes = spiread_fifo( buffer + readBytes_all / 2 ) )
    readBytes_all += readBytes;
  if ( readBytes_all == 0 )
    return;

  if( digitalRead( 4 ) == 1 ){
  int x = buffer[ 0 ];
  int y = buffer[ 1 ];
  int z = buffer[ 2 ];
  double m = sqrt( x * x + y * y + z * z ) / 2048;
  if(  m > 2.5 )
    Serial.println( m );

  BUTTONHandle();
  }
}

КОД MPU9250:

#include <SPI.h>

#define SCK 18
#define MISO 19
#define MOSI 23
#define SS 5
#define INT 34

SPIClass MPU9250( VSPI );
SPISettings settingsA( 1000000, MSBFIRST, SPI_MODE3 );
SPISettings settingsB( 20000000, MSBFIRST, SPI_MODE3 );

volatile int cnt = 0;

void IRAM_ATTR onInterrupt() {
  portENTER_CRITICAL_ISR(&mux);
  cnt++;
  portEXIT_CRITICAL_ISR(&mux);
}

void spiwrite( byte a, byte b ) {

  MPU9250.beginTransaction( settingsA );
  digitalWrite( SS, LOW );
  MPU9250.transfer( a );
  MPU9250.transfer( b );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
}

byte spiread( byte a ) {

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( a | 0x80 );
  byte r = MPU9250.transfer( 0x00 );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();

  return r;
}

int spiread_fifo( volatile short * buffer ) {

  int fifo_len = spiread( 0x72 ) * 256 + spiread( 0x73 );
  //  fifo_len += 12;
  //  fifo_len = fifo_len / 12 * 12;

  if ( fifo_len > 512 )
    return -1;

  if ( fifo_len == 0 )
    return 0;

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( 0x74 | 0x80 );
  MPU9250.transfer( 0x00 ); // if I use SPI CLOCK more than 8~12Mhz, it gives me duplicated byte at the beginning. So just drop one of them.
  for ( int i = 0; i < 3; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  for ( int i = 3; i < fifo_len / 2; i++ )
    MPU9250.transfer16( 0x00 );
  //  for( int i = fifo_len / 2 + 1; i < fifo_len; i++ )
  //    buffer[ i ] = 0;
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
  for ( int i = 0; i < 12; i++ )
    __asm__ __volatile__ ("nop\n\t");

  return fifo_len;
}

void spiread_raw( volatile short * buffer ) {

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( 0x3b | 0x80 );
  for ( int i = 0; i < 3; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
  for ( int i = 0; i < 12; i++ )
    __asm__ __volatile__ ("nop\n\t");
}

void spiread_raw_gyr( volatile short * buffer ) {

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( 0x43 | 0x80 );
  for ( int i = 0; i < 3; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
  for ( int i = 0; i < 12; i++ )
    __asm__ __volatile__ ("nop\n\t");
}

void spiread_raw_accgyr( volatile short * buffer ) {

  MPU9250.beginTransaction( settingsB );
  digitalWrite( SS, LOW );
  MPU9250.transfer( 0x3b | 0x80 );
  for ( int i = 0; i < 3; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  MPU9250.transfer16( 0x00 );
  for ( int i = 3; i < 6; i++ )
    buffer[ i ] = MPU9250.transfer16( 0x00 );
  digitalWrite( SS, HIGH );
  MPU9250.endTransaction();
  for ( int i = 0; i < 12; i++ )
    __asm__ __volatile__ ("nop\n\t");
}

void MPU9250Setup(){

  pinMode( SS, OUTPUT );
  pinMode( SCK, OUTPUT );
  pinMode( MOSI, OUTPUT );
  pinMode( INT, INPUT_PULLUP );
  pinMode( MISO, INPUT );
  pinMode( 4, INPUT );

  MPU9250.begin( SCK, MISO, MOSI, SS ); //CLK,MISO,MOIS,SS
  attachInterrupt( digitalPinToInterrupt( INT ), onInterrupt, FALLING );

  spiwrite( 0x68, 0x07 );
  spiwrite( 0x6A, 0x55 ); // FIFO_EN = 1, FIFO_RST = 1;
  spiwrite( 0x19, 0x00 ); // SMPLRT_DIV = 0
  spiwrite( 0x1B, 0x18 ); // GYRO_FS_SEL = 3, Fchoice_b = 0
  spiwrite( 0x1C, 0x18 ); // ACCEL_FS_SEL = 3
  spiwrite( 0x1D, 0x08 ); // accel_fchoice_b = 1
  //  spiwrite( 0x23, 0x78 ); // TEMP_OUT = 0, GYRO_XOUT = 1, GYRO_YOUT = 1, GYRO_ZOUT = 1, ACCEL = 1
  //  spiwrite( 0x23, 0x79 ); // TEMP_OUT = 0, GYRO_XOUT = 0, GYRO_YOUT = 0, GYRO_ZOUT = 0, ACCEL = 1
  spiwrite( 0x23, 0x08 ); // TEMP_OUT = 0, GYRO_XOUT = 0, GYRO_YOUT = 0, GYRO_ZOUT = 0, ACCEL = 1
  spiwrite( 0x37, 0x10 ); // INT_ANYRD_2CLEAR = 1
  spiwrite( 0x38, 0xC1 ); // ACTL = 1, OPEN = 1, RAW_RDY_EN = 1
  spiwrite( 0x1A, 0x07 ); // FIFO_MODE = 0, EXT_SYNC_SET = 0, DLPF_CFG = 7
}

КОД прошивки OTA:

#include <WiFi.h>
#include "esp_wifi.h"
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "XXXXXX";
const char* password = "XXXXXX";

void OTASetup(){


  delay( 100 );
  esp_wifi_set_max_tx_power( -100 );
  WiFi.mode( WIFI_STA );
  WiFi.setHostname( "LOLIN_D32_PRO_Sunkyue" );
  delay( 100 );
  WiFi.begin( ssid, password );
  while( WiFi.waitForConnectResult() != WL_CONNECTED ){

    Serial.println( "Connection Failed! Rebooting..." );
    delay( 10 );
    ESP.restart();
  }

  ArduinoOTA.setPort(53232);
  ArduinoOTA.setHostname("LOLIN_D32_PRO_Sunkyue");
  ArduinoOTA.setPassword("XXXXXX");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void OTAHandle(){

  ArduinoOTA.handle();
}

КОД ВЕБ-СЕРВЕРА:

#include <WiFiClient.h>
#include <WebServer.h>

WebServer server(80);


void handleRoot() {

  char temp[400];
  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;

  snprintf(temp, 400,

           "<html>\
  <head>\
    <meta http-equiv='refresh' content='0.5'/>\
    <title>ESP32 Demo</title>\
    <style>\
      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
    </style>\
  </head>\
  <body>\
    <h1>Hello from ESP32!</h1>\
    <p>Uptime: %02d:%02d:%02d</p>\
    <img src=\"/test.svg\" />\
  </body>\
</html>",

           hr, min % 60, sec % 60
          );
  server.send(200, "text/html", temp);
}

void handleNotFound() {

  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }

  server.send(404, "text/plain", message);
}

void drawGraph() {
  String out = "";
  char temp[100];
  out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n";
  out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n";
  out += "<g stroke=\"black\">\n";
  int y = rand() % 130;
  for (int x = 10; x < 390; x += 10) {
    int y2 = rand() % 130;
    sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2);
    out += temp;
    y = y2;
  }
  out += "</g>\n</svg>\n";

  server.send(200, "image/svg+xml", out);
}

void WEBSERVERSetup(){

  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", handleRoot);
  server.on("/test.svg", drawGraph);
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });
  server.onNotFound(handleNotFound);
  server.begin();
}

void WEBSERVERHandle(){
  server.handleClient();
}

1 Ответ

0 голосов
/ 11 мая 2019

Я вижу два решения для однопроцессорного решения (поскольку вы не указали конечные цели, одно может быть более оптимальным, чем другое):

  1. Если можно пропустить приблизительно 15-25 мс данных (постукивание датчика должно все еще регистрироваться,) Измените spiread_fifo(...) на spiread_raw_accgyr(buffer) в loop(). Это будет считывать текущие значения в буфер во время выполнения. Это определенно не подходит для расчета местоположения или сейсмических событий.

  2. Считайте и проанализируйте необходимые данные в подпрограмме прерывания (либо аппаратный вывод из MPU9250, либо таймер), поскольку веб-клиент гораздо более простителен для задержек (в пределах разумного).

В любом случае, расчеты должны быть оптимизированы для уменьшения количества команд (ESP32 не имеет FPU, поэтому все операции с плавающей запятой должны быть эмулированы в программном обеспечении):

Строки:

double m = sqrt( x * x + y * y + z * z ) / 2048;
  if(  m > 2.5 )

Может быть упрощено (если требуется совершенная (сферическая) точность) путем алгебраической возведения в квадрат обе стороны уравнения для:

double m =  (x * x + y * y + z * z)  / 4194304;
  if (m > 6.25)

Или (желательно, но с несколько меньшей точностью при объединении осей):

double m =  ((abs(x) + abs(y) + abs(z))  / 2048); // Manhattan distance(a diamond in 2D, a four sided, double pyramid in 3d)
if (m > 2.5)

Последняя строка на странице 6 таблицы MPU9250 : гласит:

последовательный интерфейс SPI 1 МГц для связи со всеми регистрами

Следующая строка:

20 МГц SPI последовательный интерфейс для считывания датчиков и регистров прерываний

Регистр FIFO ( раздел 4.17 таблицы называет FIFO регистром) не является ни датчиком, ни регистром прерываний; поэтому связь должна быть ограничена до 1 МГц. Любое сканирование выше этой частоты МОЖЕТ (и будет в случае несинфазных запросов) давать недействительные / непостоянные результаты.

Мне не удалось найти ссылку на библиотеку MPU9250 или приведенные команды, чтобы убедиться, что это так в вашем коде.

...