Forum: Mikrocontroller und Digitale Elektronik ESP32 I2C Daten im Interrupt auslesen - WiFi stört.


von A. B. (sfalbuer)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich möchte Interruptbasiert mit 1600hz jeweils 6 Bytes über I2C aus 
einem Sensor auslesen. Das klappt eigentlich auch und auf dem 
Oszilloskop kann ich erkennen dass die I2C Routine schnell genug ist um 
zwischen den Interrupts die Daten auszulesen, auch werden keine 
Interrupts verpasst. Leider verändert sich die Situation wenn ich mit 
WiFi.h und WiFi.begin(); den ESP32 ins WLAN bringe. Dann kommt es häufig 
vor dass das Auslesen der sechs bytes zu lange dauert und der nächste 
Interrupt verpennt wird. Offensichtlich stört also das WiFi irgendwie 
das RTOS. Weiß jemand woran das liegen könnte? Auf dem Screenshot sieht 
man das ganz gut. Unten der DataReady Interrupt des Sensors und oben die 
Funktion des Sensors die auf dem Bild gleich zwei mal länger braucht als 
normal.

1
#include <Wire.h>
2
#include <Arduino.h>
3
4
5
TwoWire I2Ca = TwoWire(0); //i2C instance
6
7
#define SDA1 21 
8
#define SCL1 22 
9
SemaphoreHandle_t dataRdy;
10
11
void IRAM_ATTR isr() {
12
  BaseType_t taskWoken = pdFALSE;  
13
  if(dataRdy != NULL) xSemaphoreGiveFromISR(dataRdy, &taskWoken);
14
  if(taskWoken == pdTRUE) portYIELD_FROM_ISR();
15
}
16
17
void IRAM_ATTR *readI2c(int16_t &x, int16_t &y, int16_t &z){
18
  int16_t accData[3];
19
  byte devAddr = 0x18;
20
  byte regAddr = 0x12;
21
  Wire.writeTransmission(devAddr, &regAddr, 1, false);
22
  Wire.readTransmission(devAddr, (uint8_t*)accData, 6, true);
23
  x = accData[0];
24
  y = accData[1];
25
  z = accData[2];
26
}
27
28
void readI2cTsk(void *parameter){
29
  while(dataRdy == NULL){
30
    vTaskDelay(1);
31
  }
32
  while(1){
33
    int16_t x,y,z;
34
    if(xSemaphoreTake(dataRdy, portMAX_DELAY) == pdTRUE){
35
      digitalWrite(15,HIGH); //Channel 1
36
      readI2c(x,y,z); 
37
      digitalWrite(15,LOW); 
38
    }
39
  }
40
}
41
void setup() {
42
  I2Ca.begin(SDA1,SCL1,800000);
43
  Serial.begin(921600);
44
  while (!Serial) {}; // wait for Arduino Serial Monitor to be ready
45
  attachInterrupt(23, isr, RISING);
46
  pinMode(LED_BUILTIN, OUTPUT); 
47
  pinMode(15, OUTPUT);
48
  dataRdy = xSemaphoreCreateBinary();
49
  xTaskCreatePinnedToCore(readI2cTsk, "i2c_task", 1024, NULL, 20, 0, 1);
50
  
51
}
52
53
void loop() {
54
  vTaskDelay(100);
55
}

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

A. B. schrieb:
> Auf dem Screenshot sieht man das ganz gut. Unten der DataReady Interrupt
> des Sensors und oben die Funktion des Sensors
Für mich sieht "die Funktion" irgendwie völlig beliebig aus. Was soll 
denn da wie "funktionieren"?

> die auf dem Bild gleich zwei mal länger braucht als normal.
Woran erkennt man das? Wie sollte das denn korrekt aussehen?

Soll da auf jede steigende Flanke von "blau" ein kurzer High-Impuls auf 
"gelb" kommen?

> Offensichtlich stört also das WiFi irgendwie das RTOS.
> Weiß jemand woran das liegen könnte?
Augenscheinlich gibt da wer die Interrupts nicht schnell genug frei. Das 
ist das Hauptproblem bei schlecht programmierten Treibern.

von A. B. (sfalbuer)


Lesenswert?

Moin,

Ja also hier:
1
if(xSemaphoreTake(dataRdy, portMAX_DELAY) == pdTRUE){
2
      digitalWrite(15,HIGH); //Channel 1
3
      readI2c(x,y,z); 
4
      digitalWrite(15,LOW); 
5
    }

Wird Pin15 (Kanal 1 auf dem Oszi) auf HIGH gezogen während die Funktion 
den Sensor über I2C ausliest. Damit sieht man in etwa wie lange die 
Funktion zugange ist.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

A. B. schrieb:
> Damit sieht man in etwa wie lange die Funktion zugange ist.
Ich würde mir gleich mal die eigentliche Kommunikation/Reaktion auf dem 
I2C Bus ansehen.

Könnte auch sein, dass der Scheduler der readI2cTsk nicht wichtig genug 
ist. Das ist das Problem bei solchen Multitasking-Dingern: wie sag ich 
dem Scheduler, dass ich mir selbst der Wichtigste bin? Und wie 
beeinflusse ich dadurch das Betriebssystem?

von Nils W. (derniwi)


Lesenswert?

Hallo,

ich habe in einem anderen Zusammenhang im Prinzip das gleiche Problem. 
Sobald WiFi aktiv ist, läuft "mein" Programm nicht mehr so zeitgenau, 
wie ohne. Dass WiFi im Hintergrund aktiv ist und somit durch den 
"unsichtbaren" Scheduler auch Prozessorzeit bekommt, ist natürlich klar. 
Evtl. würde es helfen, hätte man hier ein paar wenige Einflüsse auf die 
ganzen Zusammenhänge. Ich kann zwar einzelne Teile auf einen 
Prozessorkern legen und nur dort laufen lassen (ich nutze einen alten 
ESP32-WROOM-32), aber ich habe bisher nicht wirklich sinnvolle 
Dokumentation über diese Zusammenhänge gefunden, also ESP32, FreeRTOS, 
Scheduler und Nutzung von Interrupts für Systemkomponenten / Treiber. 
Anders gesagt, WiFi kann aktiviert werden und reagiert z.B. auf versch. 
IP-Grundfunktionen wie z.B. einen Ping, d.h. der ESP antwortet auf 
Ping-Anfragen aus dem Netzwerk. Das geschieht dann irgendwo im Treiber 
für WiFi / Netzwerk, und hierauf hat man keinen Einfluss. Für 
zeitkritische Punkte müsste man also die Möglichkeit haben, andere 
Interrupts vorübergehend zu deaktivieren, mit dem Wissen, dass hier 
natürlich dann etwas verpasst werden kann.

Mein Fazit: mit dem ESP32 kann man viel machen, aber die volle Kontrolle 
hat man mit FreeRTOS und der Arduino-Umgebung nicht.

Gruß
Nils

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.