Webserver access alters MPU9250's signal.

kimsunk
Posts: 3
Joined: Fri Apr 26, 2019 6:39 am

Webserver access alters MPU9250's signal.

Postby kimsunk » Fri Apr 26, 2019 6:56 am

I'm writing a program which reads MPU9250's accelerometer&gyro data using MPU9250's internal FIFO and serves web interface.

Without web access, everything is fine.

However, on the exact timing of web request, bytes read on that timing is changed.

My current code just simply shows template webpage and prints IMU accelerometer value only if its magnitude is greater than 2.5. So, if I do not touch MPU9250 sensor, its value should be between 0.9~1.1. However, it prints some wrong values greater than 2.5 when the webpage is refreshed (currently auto-refreshing in 0.5 seconds ) although MPU9250 sensor is not touched at all.

My assumptions are,

1. strong RF signal affects SPI bus so signals are altered.
2. wifi TX routine is called during MPU9250 FIFO readout process and it causes data drop during FIFO read.

I'm using LOLIN D32 PRO board. and MPU9250 is connected its default VSPI bus.

Any possible solution would be appreciated.


MAIN CODE :
  1. extern volatile int cnt;
  2.  
  3. volatile short* buffer;
  4. volatile short* buffer2;
  5. volatile unsigned long *timestamp;
  6.  
  7. portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
  8.  
  9. void printHex( int num, int precision) {
  10.  
  11.   char tmp[16];
  12.   char format[128];
  13.  
  14.   sprintf(format, "%%.%dX ", precision);
  15.  
  16.   sprintf(tmp, format, num);
  17.   if ( strlen( tmp ) > precision + 1 ) {
  18.  
  19.     int l = strlen( tmp ) - precision - 1;
  20.     for ( int i = 0; i < precision + 2; i++ ) {
  21.  
  22.       tmp[ i ] = tmp[ i + l ];
  23.     }
  24.   }
  25.  
  26.   Serial.print(tmp);
  27. }
  28.  
  29. void setup() {
  30.  
  31.   Serial.begin( 2000000 );
  32.  
  33.   Serial.println( "Turning on...." );
  34.  
  35.   buffer = ( short * )ps_malloc( 1000000 );
  36.   buffer2 = ( short * )ps_malloc( 1000000 );
  37.  
  38.   BUTTONSetup();
  39.   MPU9250Setup();
  40.   OTASetup();
  41.   WEBSERVERSetup();
  42.  
  43.   Serial.println( "Setup finished." );
  44. }
  45.  
  46. void loop() {
  47.  
  48.   OTAHandle();
  49.   WEBSERVERHandle();
  50.  
  51.   int readBytes = 0, readBytes_all = 0;
  52.  
  53.   while( readBytes = spiread_fifo( buffer + readBytes_all / 2 ) )
  54.     readBytes_all += readBytes;
  55.   if ( readBytes_all == 0 )
  56.     return;
  57.  
  58.   if( digitalRead( 4 ) == 1 ){
  59.   int x = buffer[ 0 ];
  60.   int y = buffer[ 1 ];
  61.   int z = buffer[ 2 ];
  62.   double m = sqrt( x * x + y * y + z * z ) / 2048;
  63.   if(  m > 2.5 )
  64.     Serial.println( m );
  65.  
  66.   BUTTONHandle();
  67.   }
  68. }
MPU9250 CODE :
  1. #include <SPI.h>
  2.  
  3. #define SCK 18
  4. #define MISO 19
  5. #define MOSI 23
  6. #define SS 5
  7. #define INT 34
  8.  
  9. SPIClass MPU9250( VSPI );
  10. SPISettings settingsA( 1000000, MSBFIRST, SPI_MODE3 );
  11. SPISettings settingsB( 20000000, MSBFIRST, SPI_MODE3 );
  12.  
  13. volatile int cnt = 0;
  14.  
  15. void IRAM_ATTR onInterrupt() {
  16.   portENTER_CRITICAL_ISR(&mux);
  17.   cnt++;
  18.   portEXIT_CRITICAL_ISR(&mux);
  19. }
  20.  
  21. void spiwrite( byte a, byte b ) {
  22.  
  23.   MPU9250.beginTransaction( settingsA );
  24.   digitalWrite( SS, LOW );
  25.   MPU9250.transfer( a );
  26.   MPU9250.transfer( b );
  27.   digitalWrite( SS, HIGH );
  28.   MPU9250.endTransaction();
  29. }
  30.  
  31. byte spiread( byte a ) {
  32.  
  33.   MPU9250.beginTransaction( settingsB );
  34.   digitalWrite( SS, LOW );
  35.   MPU9250.transfer( a | 0x80 );
  36.   byte r = MPU9250.transfer( 0x00 );
  37.   digitalWrite( SS, HIGH );
  38.   MPU9250.endTransaction();
  39.  
  40.   return r;
  41. }
  42.  
  43. int spiread_fifo( volatile short * buffer ) {
  44.  
  45.   int fifo_len = spiread( 0x72 ) * 256 + spiread( 0x73 );
  46.   //  fifo_len += 12;
  47.   //  fifo_len = fifo_len / 12 * 12;
  48.  
  49.   if ( fifo_len > 512 )
  50.     return -1;
  51.  
  52.   if ( fifo_len == 0 )
  53.     return 0;
  54.  
  55.   MPU9250.beginTransaction( settingsB );
  56.   digitalWrite( SS, LOW );
  57.   MPU9250.transfer( 0x74 | 0x80 );
  58.   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.
  59.   for ( int i = 0; i < 3; i++ )
  60.     buffer[ i ] = MPU9250.transfer16( 0x00 );
  61.   for ( int i = 3; i < fifo_len / 2; i++ )
  62.     MPU9250.transfer16( 0x00 );
  63.   //  for( int i = fifo_len / 2 + 1; i < fifo_len; i++ )
  64.   //    buffer[ i ] = 0;
  65.   digitalWrite( SS, HIGH );
  66.   MPU9250.endTransaction();
  67.   for ( int i = 0; i < 12; i++ )
  68.     __asm__ __volatile__ ("nop\n\t");
  69.  
  70.   return fifo_len;
  71. }
  72.  
  73. void spiread_raw( volatile short * buffer ) {
  74.  
  75.   MPU9250.beginTransaction( settingsB );
  76.   digitalWrite( SS, LOW );
  77.   MPU9250.transfer( 0x3b | 0x80 );
  78.   for ( int i = 0; i < 3; i++ )
  79.     buffer[ i ] = MPU9250.transfer16( 0x00 );
  80.   digitalWrite( SS, HIGH );
  81.   MPU9250.endTransaction();
  82.   for ( int i = 0; i < 12; i++ )
  83.     __asm__ __volatile__ ("nop\n\t");
  84. }
  85.  
  86. void spiread_raw_gyr( volatile short * buffer ) {
  87.  
  88.   MPU9250.beginTransaction( settingsB );
  89.   digitalWrite( SS, LOW );
  90.   MPU9250.transfer( 0x43 | 0x80 );
  91.   for ( int i = 0; i < 3; i++ )
  92.     buffer[ i ] = MPU9250.transfer16( 0x00 );
  93.   digitalWrite( SS, HIGH );
  94.   MPU9250.endTransaction();
  95.   for ( int i = 0; i < 12; i++ )
  96.     __asm__ __volatile__ ("nop\n\t");
  97. }
  98.  
  99. void spiread_raw_accgyr( volatile short * buffer ) {
  100.  
  101.   MPU9250.beginTransaction( settingsB );
  102.   digitalWrite( SS, LOW );
  103.   MPU9250.transfer( 0x3b | 0x80 );
  104.   for ( int i = 0; i < 3; i++ )
  105.     buffer[ i ] = MPU9250.transfer16( 0x00 );
  106.   MPU9250.transfer16( 0x00 );
  107.   for ( int i = 3; i < 6; i++ )
  108.     buffer[ i ] = MPU9250.transfer16( 0x00 );
  109.   digitalWrite( SS, HIGH );
  110.   MPU9250.endTransaction();
  111.   for ( int i = 0; i < 12; i++ )
  112.     __asm__ __volatile__ ("nop\n\t");
  113. }
  114.  
  115. void MPU9250Setup(){
  116.  
  117.   pinMode( SS, OUTPUT );
  118.   pinMode( SCK, OUTPUT );
  119.   pinMode( MOSI, OUTPUT );
  120.   pinMode( INT, INPUT_PULLUP );
  121.   pinMode( MISO, INPUT );
  122.   pinMode( 4, INPUT );
  123.  
  124.   MPU9250.begin( SCK, MISO, MOSI, SS ); //CLK,MISO,MOIS,SS
  125.   attachInterrupt( digitalPinToInterrupt( INT ), onInterrupt, FALLING );
  126.  
  127.   spiwrite( 0x68, 0x07 );
  128.   spiwrite( 0x6A, 0x55 ); // FIFO_EN = 1, FIFO_RST = 1;
  129.   spiwrite( 0x19, 0x00 ); // SMPLRT_DIV = 0
  130.   spiwrite( 0x1B, 0x18 ); // GYRO_FS_SEL = 3, Fchoice_b = 0
  131.   spiwrite( 0x1C, 0x18 ); // ACCEL_FS_SEL = 3
  132.   spiwrite( 0x1D, 0x08 ); // accel_fchoice_b = 1
  133.   //  spiwrite( 0x23, 0x78 ); // TEMP_OUT = 0, GYRO_XOUT = 1, GYRO_YOUT = 1, GYRO_ZOUT = 1, ACCEL = 1
  134.   //  spiwrite( 0x23, 0x79 ); // TEMP_OUT = 0, GYRO_XOUT = 0, GYRO_YOUT = 0, GYRO_ZOUT = 0, ACCEL = 1
  135.   spiwrite( 0x23, 0x08 ); // TEMP_OUT = 0, GYRO_XOUT = 0, GYRO_YOUT = 0, GYRO_ZOUT = 0, ACCEL = 1
  136.   spiwrite( 0x37, 0x10 ); // INT_ANYRD_2CLEAR = 1
  137.   spiwrite( 0x38, 0xC1 ); // ACTL = 1, OPEN = 1, RAW_RDY_EN = 1
  138.   spiwrite( 0x1A, 0x07 ); // FIFO_MODE = 0, EXT_SYNC_SET = 0, DLPF_CFG = 7
  139. }
  140.  
Wireless OTA CODE :
  1. #include <WiFi.h>
  2. #include "esp_wifi.h"
  3. #include <ESPmDNS.h>
  4. #include <WiFiUdp.h>
  5. #include <ArduinoOTA.h>
  6.  
  7. const char* ssid = "XXXX";
  8. const char* password = "XXXX";
  9.  
  10. void OTASetup(){
  11.  
  12.  
  13.   delay( 100 );
  14.   esp_wifi_set_max_tx_power( -100 );
  15.   WiFi.mode( WIFI_STA );
  16.   WiFi.setHostname( "LOLIN_D32_PRO_Sunkyue" );
  17.   delay( 100 );
  18.   WiFi.begin( ssid, password );
  19.   while( WiFi.waitForConnectResult() != WL_CONNECTED ){
  20.  
  21.     Serial.println( "Connection Failed! Rebooting..." );
  22.     delay( 10 );
  23.     ESP.restart();
  24.   }
  25.  
  26.   ArduinoOTA.setPort(53232);
  27.   ArduinoOTA.setHostname("LOLIN_D32_PRO_Sunkyue");
  28.   ArduinoOTA.setPassword("XXXX");
  29.  
  30.   ArduinoOTA
  31.     .onStart([]() {
  32.       String type;
  33.       if (ArduinoOTA.getCommand() == U_FLASH)
  34.         type = "sketch";
  35.       else // U_SPIFFS
  36.         type = "filesystem";
  37.  
  38.       // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
  39.       Serial.println("Start updating " + type);
  40.     })
  41.     .onEnd([]() {
  42.       Serial.println("\nEnd");
  43.     })
  44.     .onProgress([](unsigned int progress, unsigned int total) {
  45.       Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  46.     })
  47.     .onError([](ota_error_t error) {
  48.       Serial.printf("Error[%u]: ", error);
  49.       if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
  50.       else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
  51.       else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
  52.       else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
  53.       else if (error == OTA_END_ERROR) Serial.println("End Failed");
  54.     });
  55.  
  56.   ArduinoOTA.begin();
  57.  
  58.   Serial.println("Ready");
  59.   Serial.print("IP address: ");
  60.   Serial.println(WiFi.localIP());
  61. }
  62.  
  63. void OTAHandle(){
  64.  
  65.   ArduinoOTA.handle();
  66. }
Webserver CODE :
  1. #include <WiFiClient.h>
  2. #include <WebServer.h>
  3.  
  4. WebServer server(80);
  5.  
  6.  
  7. void handleRoot() {
  8.  
  9.   char temp[400];
  10.   int sec = millis() / 1000;
  11.   int min = sec / 60;
  12.   int hr = min / 60;
  13.  
  14.   snprintf(temp, 400,
  15.  
  16.            "<html>\
  17.  <head>\
  18.    <meta http-equiv='refresh' content='0.5'/>\
  19.    <title>ESP32 Demo</title>\
  20.    <style>\
  21.      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
  22.    </style>\
  23.  </head>\
  24.  <body>\
  25.    <h1>Hello from ESP32!</h1>\
  26.    <p>Uptime: %02d:%02d:%02d</p>\
  27.    <img src=\"/test.svg\" />\
  28.  </body>\
  29. </html>",
  30.  
  31.            hr, min % 60, sec % 60
  32.           );
  33.   server.send(200, "text/html", temp);
  34. }
  35.  
  36. void handleNotFound() {
  37.  
  38.   String message = "File Not Found\n\n";
  39.   message += "URI: ";
  40.   message += server.uri();
  41.   message += "\nMethod: ";
  42.   message += (server.method() == HTTP_GET) ? "GET" : "POST";
  43.   message += "\nArguments: ";
  44.   message += server.args();
  45.   message += "\n";
  46.  
  47.   for (uint8_t i = 0; i < server.args(); i++) {
  48.     message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  49.   }
  50.  
  51.   server.send(404, "text/plain", message);
  52. }
  53.  
  54. void drawGraph() {
  55.   String out = "";
  56.   char temp[100];
  57.   out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n";
  58.   out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n";
  59.   out += "<g stroke=\"black\">\n";
  60.   int y = rand() % 130;
  61.   for (int x = 10; x < 390; x += 10) {
  62.     int y2 = rand() % 130;
  63.     sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2);
  64.     out += temp;
  65.     y = y2;
  66.   }
  67.   out += "</g>\n</svg>\n";
  68.  
  69.   server.send(200, "image/svg+xml", out);
  70. }
  71.  
  72. void WEBSERVERSetup(){
  73.  
  74.   if (MDNS.begin("esp32")) {
  75.     Serial.println("MDNS responder started");
  76.   }
  77.  
  78.   server.on("/", handleRoot);
  79.   server.on("/test.svg", drawGraph);
  80.   server.on("/inline", []() {
  81.     server.send(200, "text/plain", "this works as well");
  82.   });
  83.   server.onNotFound(handleNotFound);
  84.   server.begin();
  85. }
  86.  
  87. void WEBSERVERHandle(){
  88.   server.handleClient();
  89. }

kimsunk
Posts: 3
Joined: Fri Apr 26, 2019 6:39 am

Re: Webserver access alters MPU9250's signal.

Postby kimsunk » Tue Apr 30, 2019 2:56 am

Self solved.

It was because webserver handler blocks dequeuing MPU 9250's FIFO more than 10ms and the FIFO is filled around 10ms.

Solved by using multi-core approach. Dual core is a lot better than a single core...


xTaskCreatePinnedToCore(
handleWebThings, /* Function to implement the task */
"handleWebThings", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
NULL, /* Task handle. */
0); /* Core where the task should run */

void handleWebThings( void* param ){

while( 1 ){

OTAHandle();
WEBSERVERHandle();
delay(1);
}
}

TomWS1
Posts: 21
Joined: Wed May 01, 2019 2:50 pm

Re: Webserver access alters MPU9250's signal.

Postby TomWS1 » Wed May 01, 2019 3:02 pm

I just moved to the ESP32 because of a similar problem, my sampling rate and processing load was too much for a standard Arduino platform. I considered using ESP8266 but this didn't have the timer resolution I needed to control the sampling. When I saw that the ESP32 had more than enough horsepower, 4 high resolution timers, AND TWO CORES, I was sold.

Like you, I've moved the 'web handling' stuff to Core 0 and this includes:
ArduinoOTA,
WebServer,
WebServerUpdate,
MQTT client (using PubSubClient).

I did find that I had to add

Code: Select all

    disableCore0WDT();
    ...
    enableCore0WDT();
within the web server upload code, otherwise I got WDT timeouts in IDLE0 task during uploads.

Works great so far. Really good stuff!!!

Tom

Who is online

Users browsing this forum: No registered users and 61 guests