Forum: Compiler & IDEs ESP32 - der unmögliche Code


von mc33sh (Gast)


Lesenswert?

Guten Abend liebe Community,

ich stehe vor einem für mich nicht lösbaren Problem.
Generell würde ich meine Programmierkenntnisse als Vorgeschritten 
bezeichnen, jedoch ist das nachfolgende Problem für mich logisch nicht 
nachvollziehbar.

Toolchain : Arduino 1.8.19
uC : ESP32 - Sparkfun Thing

Folgender Code löst auf Core 1 ein Core Panic'ed (IllegalInctruction) 
aus.
1
void LC_SetHPD(boolean lvl) {
2
   byte testdata = ReadByte(0x06);
3
}
4
5
void LC_Init() {
6
    LC_SetHPD(false);
7
}
8
9
10
byte ReadByte(byte adrr) {
11
12
}
13
14
void setup() {
15
  
16
  delay(1000);
17
  Serial.begin(115200);
18
  Serial.println("Init System"); 
19
  delay(1000);
20
  LC_Init(); 
21
22
  
23
}
24
25
26
void loop() {
27
   
28
   
29
}

wenn ich folgende Zeile lösche, gibt es keine Panic Probleme, und der uC 
startet auch nicht neu.
1
  byte testdata = ReadByte(0x06);

Auch auf jeder anderen mir zugänglichen Microcontroller Architektur (AVR 
8bit, SAMD) läuft der code ohne Probleme.
Nur eben auf dem ESP32 kommt es zu einer Core1 Panic.

Das ganze ist eigentlich ein deutlich umfangreicherer Code, jedoch 
konnte ich es auf diesen Sektion reduzieren.

Ich bin extrem gespannt welcher verrückte Mechanismus sich dahinter 
versteckt.

Vielen Dank für die Hilfe !

von dummschwaetzer (Gast)


Lesenswert?

Schalt mal Warnungen an!
Das das da oben compiliert ist ein Wunder.
>byte ReadByte(byte adrr) {
>
>}
da fehlt ein return wert;
>void LC_SetHPD(boolean lvl) {
>
>  byte testdata = ReadByte(0x06);
>
>}
und weiter? Was soll mit testdata passieren, das wird wahrscheinlich 
wegoptimiert und damit dein komplettes
LC_Init();

von MaWin (Gast)


Lesenswert?

mc33sh schrieb:
> byte ReadByte(byte adrr) {
> }

Was soll das werden ohne return value ?

Da gab doch sicher eine Compilerwarnung.

von mc33sh (Gast)


Lesenswert?

Der fehlende return ist mir bewusst, und im eigentlich code wird diese 
Funktion zum lesen von i2c verwendet.
jedoch in beiden fällen - gibt es die Core1 Panic.
Sofern der Compiler das nun wegoptimiert , sollte es doch erst recht zu 
keinem Panic state kommen ?
1
byte ReadByte(byte adrr) {
2
  
3
   uint8_t p_data;
4
   p_data = 0;
5
6
   Wire.beginTransmission(LT8619_I2C_ADR); 
7
   Wire.write(RegAddr);             // sends value byte  
8
   Wire.endTransmission(false);
9
10
   if (Wire.requestFrom(LT8619_I2C_ADR, 1) == 1) {    
11
       p_data = Wire.read();    
12
   }
13
   
14
    return p_data;
15
}

von Peter D. (peda)


Lesenswert?

Versuche mal, einen Code zu posten, der ohne Warnungen und Fehler 
compiliert. Und schreibe ihn nicht aus dem Gedächtnis nach, sondern 
benutze C&P.
Am besten poste ihn als Dateianhang (*.c). Kleine Schnipsel im Post 
eingebettet, nutzen nur selten was.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Es gibt hoffentlich auch noch eine Funktionsdeklaration für ReadByte die 
vor LC_SetHPD() steht. Ansonsten definiert der Compiler sich nämlich 
selbst was zusammen. (In diesem Fall sowas wie "int ReadByte(int)"). Auf 
ARM oder AVR8 ist dass wegen deren ABI egal. Beim Tensilica Xtensa LX 
(Der steckt im ESP32) müsste man deren ABI mal nachlesen.

von Flötenschlumpf (Gast)


Lesenswert?

Darf man überhaupt von nicht durch vier teilbaren Adressen lesen?

von Andreas M. (amesser)


Lesenswert?

Flötenschlumpf schrieb:
> Darf man überhaupt von nicht durch vier teilbaren Adressen lesen?

Natürlich. x86 kann das ohne besondere Tricksereien, Bei ARM Cortex geht 
das in entsprechend getagten Speicherbereichen auch. (Wird dann von der 
MMU/MPU implizit auf mehrere Aligned Zugriffe umgemappt) Bei Zugriffen 
auf andere Speicherbereiche oder bei älteren ARM CPUs im Allgemeinen 
muss der Compiler dann z.B. statt einem 4-Byte Zugriff eben 4 einzelne 
1-Byte-Zugriffe machen ud das dann zusammensetzen.

von 900ss (900ss)


Lesenswert?

Andreas M. schrieb:
> Natürlich.

Sorry, das nun wirklich nicht natürlich. :)

Das es beim ESP32 (und anderen geht) funktioniert, ok.
Aber versuche das z.B. mal auf einem SPARC V8 (z.B. LEON2/3/4) und auch 
anderen. Es unterstützt längst nicht jede Architektur den "unligned 
access".

Edit: Ich muss eine Einschränkung nachschieben :) Ein Bytezugriff 
funktioniert "unaligned" auch beim SPARC. Aber ein Wortzugriff nicht. 
Das aber wieder geht z.B. bei x86.

: Bearbeitet durch User
von MaWin. (Gast)


Lesenswert?

900ss D. schrieb:
> Ein Bytezugriff funktioniert "unaligned" auch beim SPARC.

Wie kann ein Bytezugriff unaligned sein?

von 900ss (900ss)


Lesenswert?

MaWin. schrieb:
> Wie kann ein Bytezugriff unaligned sein?

%-/

Ja schon gut aber ich denke, jeder (außer du?) versteht, was ich meinte. 
Für dich hatte ich es sogar in "" gestellt.

: Bearbeitet durch User
von Arno (Gast)


Lesenswert?

Flötenschlumpf schrieb:
> Darf man überhaupt von nicht durch vier teilbaren Adressen lesen?

Wäre auch mein erster Verdacht gewesen. Beim ESP8266 hab ich mit
1
unsigned int i, j;
2
sscanf(buffer, "%u/%u", &i, &j);

wunderschöne Abbrüche produziert, die mit
1
alignas(4) unsigned int i;
2
alignas(4) unsigned int j;
3
sscanf(char *, "%u/%u", i, j);

behoben wurden.

Aber der hier vorgestellte Code verwendet ja überhaupt keine 
Pointer/Referenzen/Adressen, sonst hätte ich das schonmal 
angesprochen...

MfG, Arno

von A. S. (Gast)


Lesenswert?

Arno schrieb:
> Beim ESP8266 hab ich mit
> unsigned int i, j;
> sscanf(buffer, "%u/%u", &i, &j);
>
> wunderschöne Abbrüche produziert, die mit

das wäre aber arg kaputt.

von Arno (Gast)


Lesenswert?

A. S. schrieb:
> Arno schrieb:
>> Beim ESP8266 hab ich mit
>> unsigned int i, j;
>> sscanf(buffer, "%u/%u", &i, &j);
>>
>> wunderschöne Abbrüche produziert, die mit
>
> das wäre aber arg kaputt.

Wie gesagt, war so (ich hab gerade nachgesehen: die entsprechenden 
Commits in meinem Code sind von 2018...).

Die Fehlermeldung war vermutlich diese: (von 
https://forum.arduino.cc/t/brauche-hilfe-beim-debuggen-esp6266-unaligned-memory-access/651824)
> Exception 9: LoadStoreAlignmentCause: Load or store to an unaligned address

Ich hab jetzt wenig Motivation, das zu testen, ob das immer noch so ist 
;)

MfG, Arno

von Rotor (Gast)


Lesenswert?

Es gibt beim ESP32 durchaus Speicheradressen, die nur mit 4 byte 
alignment adressiert werden dürfen.

Diese liegen allerdings im Instruction Memory, um z.B. den verfügbaren 
RAM zu frisieren. Gut zu wissen, aber eher unwahrscheinlich für den TO.
1
Panic'ed (IllegalInctruction)

Der Fehler ist natürlich ärgerlich. Was da in der Toolchain wohl schief 
gelaufen ist?

Vielleicht für den Moment mal auf einen anderen Datentypen ausweichen. 
Das Programm muss ja nicht allen Programmieridealen genügen.

von Andreas M. (amesser)


Lesenswert?

900ss D. schrieb:
> Andreas M. schrieb:
>> Natürlich.
>
> Sorry, das nun wirklich nicht natürlich. :)
>
> Das es beim ESP32 (und anderen geht) funktioniert, ok.
> Aber versuche das z.B. mal auf einem SPARC V8 (z.B. LEON2/3/4) und auch
> anderen. Es unterstützt längst nicht jede Architektur den "unligned
> access".
>
> Edit: Ich muss eine Einschränkung nachschieben :) Ein Bytezugriff
> funktioniert "unaligned" auch beim SPARC. Aber ein Wortzugriff nicht.
> Das aber wieder geht z.B. bei x86.

Zitiere bitte vollständig. Die Frage war: "ob auf nicht durch vier 
Teilbare Speicheradressen zugegriffen werden darf". Soweit ich weis gibt 
es keine weltweit allgemeingültige Definition, das man das nicht darf. 
Wenn, dann ist das eventuell eine architekturspezifische Einschränkung 
und selbst dann ist es die Aufgabe des C-Compilers das korrekt 
umzusetzen, auch bei Pointern.  (Ja man kann den Compiler mittels Casts 
zu allem möglichen zwingen, aber wer das tut sollte eben auch genau 
wissen was er tut)

von 900ss (900ss)


Lesenswert?

Andreas M. schrieb:
> Zitiere bitte vollständig.

Es tut mir leid, aber den Wunsch möchte ich dir nicht erfüllen. Dann 
werden am Ende die Beiträge kilometerlang und unübersichtlich. Die 
Threads werden unnötig lang mit redundanten Informationen. Als Referenz 
zu deinem Beitrag reicht das kurze Zitat. Jeder kann dann nachlesen. 
Meine Meinung.

Zum Thema "unaligned". Natürlich sorgt der Compiler dafür, dass er 
Pointer richtig initialisiert, das ist richtig. Allerdings gibt es sehr 
oft Leute, die das nicht wissen dass sie nicht unaligned zugreifen 
dürfen und es passiert auch versehentlich, dass man Pointer auf so einer 
Maschine falsch benutzt.
Und weiter gibt es den Fall, dass ein Code wieder verwendet wird und 
dieser vorher auf einer Architektur lief der unaligned Zugriffe nichts 
ausmachten. Spätestens dann hat man ein Problem. Z.B 
Protokolldatenverarbeitung im Stream wenn das Protokoll gepackt ist 
(siehe Ethernet). Oder bei gepackten Strukturen ist es auch gerne 
gesehen, dass unaligned Zugriffe passieren. Die erwähnte SPARC V8 
Architektur ist so ein Fall, wo man aufpassen muss. Deshalb mein 
Einwand, es ist ist nicht "natürlich".

Andreas M. schrieb:
> Natürlich. x86 kann das ohne besondere Tricksereien,.....

Das ist ein ernstes Problem was hier nicht so allgemein als "natürlich" 
hingestellt werden sollte. Genause wenig ist eine little Endian Maschine 
"natürlich" weil es eben genauso big Endian gibt. Oder sollte der x86 
oder ARM das Mass der Dinge sein? Sicher nicht.

Gerade "embedded Entwickler/innen" als Anfänger sollte das bewusst sein. 
Ich habe es aber auch leider bei erfahrenen Entwicklern erlebt, dass 
diese das nicht beachtet haben und ich wunderten.

: Bearbeitet durch User
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.